From 6a3d41892ab9fbb65e4f13a56cbd5436247160c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 11:56:42 +0100 Subject: [PATCH 01/17] Workarounds for issue with "accurate depth". See #9545, #10087 --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/Common/GPUStateUtils.cpp | 1 - GPU/D3D11/GPU_D3D11.cpp | 4 +++- GPU/Directx9/GPU_DX9.cpp | 4 +++- GPU/Vulkan/GPU_Vulkan.cpp | 29 ++++++++++++++++------------- assets/compat.ini | 16 ++++++++++++++++ 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 61220a7bc3..d88431ff23 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -55,6 +55,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "RequireBufferedRendering", &flags_.RequireBufferedRendering); CheckSetting(iniFile, gameID, "RequireBlockTransfer", &flags_.RequireBlockTransfer); CheckSetting(iniFile, gameID, "DisableReadbacks", &flags_.DisableReadbacks); + CheckSetting(iniFile, gameID, "DisableAccurateDepth", &flags_.DisableAccurateDepth); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 52d49ea70b..589553f026 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -55,6 +55,7 @@ struct CompatFlags { bool RequireBufferedRendering; bool RequireBlockTransfer; bool DisableReadbacks; + bool DisableAccurateDepth; }; class IniFile; diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2c17f94d24..d19e44607a 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -696,7 +696,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo maxz += fullDepthRange; } } - // Okay. So, in our shader, -1 will map to minz, and +1 will map to maxz. float halfActualZRange = (maxz - minz) * (1.0f / 2.0f); float zScale = halfActualZRange < std::numeric_limits::epsilon() ? 1.0f : vpZScale / halfActualZRange; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 59f3241e6b..154013555c 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -206,7 +206,9 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_PREFER_CPU_DOWNLOAD; - features |= GPU_SUPPORTS_ACCURATE_DEPTH; // Breaks text in PaRappa for some reason. + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { + features |= GPU_SUPPORTS_ACCURATE_DEPTH; // Breaks text in PaRappa for some reason. + } #ifndef _M_ARM // TODO: Do proper feature detection diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index a9359d46dd..d11cbd40b2 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -187,7 +187,9 @@ void GPU_DX9::CheckGPUFeatures() { features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_PREFER_CPU_DOWNLOAD; - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { + features |= GPU_SUPPORTS_ACCURATE_DEPTH; + } D3DCAPS9 caps; ZeroMemory(&caps, sizeof(caps)); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 5fc94ca58f..50751d2ed9 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -176,6 +176,22 @@ GPU_Vulkan::~GPU_Vulkan() { void GPU_Vulkan::CheckGPUFeatures() { uint32_t features = 0; + + // Mandatory features on Vulkan, which may be checked in "centralized" code + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { + features |= GPU_SUPPORTS_ACCURATE_DEPTH; + } + features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_SUPPORTS_FBO; + features |= GPU_SUPPORTS_BLEND_MINMAX; + features |= GPU_SUPPORTS_ANY_COPY_IMAGE; + features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; + features |= GPU_SUPPORTS_LARGE_VIEWPORTS; + features |= GPU_SUPPORTS_16BIT_FORMATS; + features |= GPU_SUPPORTS_INSTANCE_RENDERING; + features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; + features |= GPU_SUPPORTS_TEXTURE_FLOAT; + if (vulkan_->GetFeaturesEnabled().wideLines) { features |= GPU_SUPPORTS_WIDE_LINES; } @@ -220,19 +236,6 @@ void GPU_Vulkan::CheckGPUFeatures() { else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { features |= GPU_ROUND_DEPTH_TO_16BIT; } - - // Mandatory features on Vulkan, which may be checked in "centralized" code - features |= GPU_SUPPORTS_ACCURATE_DEPTH; - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - features |= GPU_SUPPORTS_FBO; - features |= GPU_SUPPORTS_BLEND_MINMAX; - features |= GPU_SUPPORTS_ANY_COPY_IMAGE; - features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - features |= GPU_SUPPORTS_LARGE_VIEWPORTS; - features |= GPU_SUPPORTS_16BIT_FORMATS; - features |= GPU_SUPPORTS_INSTANCE_RENDERING; - features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; - features |= GPU_SUPPORTS_TEXTURE_FLOAT; gstate_c.featureFlags = features; } diff --git a/assets/compat.ini b/assets/compat.ini index 22a5c903c5..f8ccba0862 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -285,3 +285,19 @@ ULJS00394 = true ULJS19068 = true NPJH50518 = true # TODO: Will add some games in the future + +[DisableAccurateDepth] +# Midnight Club: LA Remix +ULUS10383 = true +ULES01144 = true +ULJS00180 = true +ULJS00267 = true +ULJM05904 = true +NPJH50440 = true +# Midnight Club 3 : DUB edition +ULUS10021 = true +ULES00108 = true + +# Shadow of Destiny (#9545) +ULUS10459 = true +NPJH50036 = true \ No newline at end of file From f7184c175362a26a1175ebd7ea6c05c5b4a57d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 12:37:03 +0100 Subject: [PATCH 02/17] Android: Update to gradle 3.0.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6013117aa1..277c10f09b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' + classpath 'com.android.tools.build:gradle:3.0.1' } } From b1fce1c61a5dc0a67ff1041f99c26bea01f7bb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 12:22:38 +0100 Subject: [PATCH 03/17] Android: Fix #9697 where we'd hang if we lacked permission and got a filename as a command. --- UI/NativeApp.cpp | 41 ++++++++++++++----- android/jni/app-android.cpp | 3 ++ .../src/org/ppsspp/ppsspp/NativeActivity.java | 2 + 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index a5d9e0605a..7667bcab39 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -43,6 +43,7 @@ #endif #include "base/display.h" +#include "base/timeutil.h" #include "base/logging.h" #include "base/NativeApp.h" #include "file/vfs.h" @@ -394,6 +395,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch const char *fileToLog = 0; const char *stateToLoad = 0; + bool gotBootFilename = false; + // Parse command line LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO; for (int i = 1; i < argc; i++) { @@ -435,18 +438,34 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch break; } } else { - if (boot_filename.empty()) { - ILOG("Boot filename found in args: %s", argv[i]); - boot_filename = argv[i]; -#ifdef _WIN32 - boot_filename = ReplaceAll(boot_filename, "\\", "/"); -#endif - skipLogo = true; + // This parameter should be a boot filename. Only accept it if we + // don't already have one. + if (!gotBootFilename) { + gotBootFilename = true; + ILOG("Boot filename found in args: '%s'", argv[i]); - std::unique_ptr fileLoader(ConstructFileLoader(boot_filename)); - if (!fileLoader->Exists()) { - fprintf(stderr, "File not found: %s\n", boot_filename.c_str()); - exit(1); + bool okToLoad = true; + if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) { + PermissionStatus status = System_GetPermissionStatus(SYSTEM_PERMISSION_STORAGE); + if (status != PERMISSION_STATUS_GRANTED) { + ELOG("Storage permission not granted. Launching without argument."); + okToLoad = false; + } else { + ILOG("Storage permission granted."); + } + } + if (okToLoad) { + boot_filename = argv[i]; +#ifdef _WIN32 + boot_filename = ReplaceAll(boot_filename, "\\", "/"); +#endif + skipLogo = true; + + std::unique_ptr fileLoader(ConstructFileLoader(boot_filename)); + if (!fileLoader->Exists()) { + fprintf(stderr, "File not found: %s\n", boot_filename.c_str()); + exit(1); + } } } else { fprintf(stderr, "Can only boot one file"); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 41745a5151..197dfec98d 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -600,6 +600,9 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init setCurrentThreadName("androidInit"); + // Makes sure we get early permission grants. + ProcessFrameCommands(env); + ILOG("NativeApp.init() -- begin"); PROFILE_INIT(); diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 58e748410f..0f70d98124 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -197,6 +197,8 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C // Let's start out granted if it was granted already. if (this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { NativeApp.sendMessage("permission_granted", "storage"); + } else { + NativeApp.sendMessage("permission_denied", "storage"); } } } From 4628334bb9e90f9a3b302689898709b829b05a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 13:58:42 +0100 Subject: [PATCH 04/17] Disable the DisableAccurateDepth compat flag on AMD/Vulkan, see #9545. Ugh. --- GPU/Vulkan/GPU_Vulkan.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 50751d2ed9..efee4d9aa1 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -177,10 +177,12 @@ GPU_Vulkan::~GPU_Vulkan() { void GPU_Vulkan::CheckGPUFeatures() { uint32_t features = 0; - // Mandatory features on Vulkan, which may be checked in "centralized" code - if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { + // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || vulkan_->GetPhysicalDeviceProperties().vendorID == VULKAN_VENDOR_AMD) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } + + // Mandatory features on Vulkan, which may be checked in "centralized" code features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_SUPPORTS_FBO; features |= GPU_SUPPORTS_BLEND_MINMAX; From 9468b3d07300603dd45a449afb9c60cdad5db8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 15:18:31 +0100 Subject: [PATCH 05/17] Add a missing break that would explain the odd AUTO mipmap test results on D3D11 and Vulkan... --- 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 3d9c23a7d7..7f2d43fdfa 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -225,8 +225,8 @@ void TextureCacheCommon::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache key.lodBias = (int)(lodBias * 256.0f); if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; - break; } + break; case GE_TEXLEVEL_MODE_CONST: case GE_TEXLEVEL_MODE_UNKNOWN: key.maxLevel = (int)(lodBias * 256.0f); From 2c86217552f04f421ff459fab2728d2f7c12d5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 15:42:01 +0100 Subject: [PATCH 06/17] Cleanup GPU vendor detection a bit, use it to avoid the issue mentioned in #9545 --- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/D3D11/GPU_D3D11.cpp | 4 ++- GPU/Directx9/GPU_DX9.cpp | 4 ++- GPU/GLES/FragmentShaderGeneratorGLES.cpp | 8 +++--- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 2 +- ext/native/gfx_es2/gpu_features.cpp | 6 ++--- ext/native/gfx_es2/gpu_features.h | 4 +-- ext/native/thin3d/thin3d.h | 12 +++++++++ ext/native/thin3d/thin3d_d3d11.cpp | 11 ++++++++ ext/native/thin3d/thin3d_d3d9.cpp | 12 +++++++++ ext/native/thin3d/thin3d_gl.cpp | 34 +++++++++++++++++------- ext/native/thin3d/thin3d_vulkan.cpp | 11 ++++++++ 13 files changed, 88 insertions(+), 24 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index fa34e321d5..4ec1aa4e70 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -400,7 +400,7 @@ void SoftwareTransform( int scissorY2 = gstate.getScissorY2() + 1; reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2); } - if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { + if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_IMGTEC) { // If alpha is not allowed to be separate, it must match for both depth/stencil and color. Vulkan requires this. bool alphaMatchesColor = gstate.isClearModeColorMask() == gstate.isClearModeAlphaMask(); bool depthMatchesStencil = gstate.isClearModeAlphaMask() == gstate.isClearModeDepthMask(); diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 154013555c..3c8490394b 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -206,7 +206,9 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_PREFER_CPU_DOWNLOAD; - if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { + + // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. See #9545 + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::AMD) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; // Breaks text in PaRappa for some reason. } diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index d11cbd40b2..5286e90166 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -187,7 +187,9 @@ void GPU_DX9::CheckGPUFeatures() { features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_PREFER_CPU_DOWNLOAD; - if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { + + // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. See #9545 + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::AMD) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 8c5486687a..c9ccc22e23 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -243,7 +243,7 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer, uint64_t *uniformM if (enableAlphaTest && !alphaTestAgainstZero) { if (bitwiseOps) { WRITE(p, "int roundAndScaleTo255i(in float x) { return int(floor(x * 255.0 + 0.5)); }\n"); - } else if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) { + } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, "float roundTo255thf(in mediump float x) { mediump float y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); } else { WRITE(p, "float roundAndScaleTo255f(in float x) { return floor(x * 255.0 + 0.5); }\n"); @@ -252,7 +252,7 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer, uint64_t *uniformM if (enableColorTest && !colorTestAgainstZero) { if (bitwiseOps) { WRITE(p, "ivec3 roundAndScaleTo255iv(in vec3 x) { return ivec3(floor(x * 255.0 + 0.5)); }\n"); - } else if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) { + } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, "vec3 roundTo255thv(in vec3 x) { vec3 y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); } else { WRITE(p, "vec3 roundAndScaleTo255v(in vec3 x) { return floor(x * 255.0 + 0.5); }\n"); @@ -436,7 +436,7 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer, uint64_t *uniformM if (alphaTestFuncs[alphaTestFunc][0] != '#') { if (bitwiseOps) { WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s int(u_alphacolorref.a)) discard;\n", alphaTestFuncs[alphaTestFunc]); - } else if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) { + } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { // Work around bad PVR driver problem where equality check + discard just doesn't work. if (alphaTestFunc != GE_COMP_NOTEQUAL) { WRITE(p, " if (roundTo255thf(v.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); @@ -485,7 +485,7 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer, uint64_t *uniformM const char *maskedFragColor = "ivec3(v_scaled.r & u_alphacolormask.r, v_scaled.g & u_alphacolormask.g, v_scaled.b & u_alphacolormask.b)"; const char *maskedColorRef = "ivec3(int(u_alphacolorref.r) & u_alphacolormask.r, int(u_alphacolorref.g) & u_alphacolormask.g, int(u_alphacolorref.b) & u_alphacolormask.b)"; WRITE(p, " if (%s %s %s) discard;\n", maskedFragColor, colorTestFuncs[colorTestFunc], maskedColorRef); - } else if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) { + } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, " if (roundTo255thv(v.rgb) %s u_alphacolorref.rgb) discard;\n", colorTestFuncs[colorTestFunc]); } else { WRITE(p, " if (roundAndScaleTo255v(v.rgb) %s u_alphacolorref.rgb) discard;\n", colorTestFuncs[colorTestFunc]); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index cf48631d02..461384eb70 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -283,7 +283,7 @@ static void SetColorUniform3Alpha(int uniform, u32 color, u8 alpha) { // This passes colors unscaled (e.g. 0 - 255 not 0 - 1.) static void SetColorUniform3Alpha255(int uniform, u32 color, u8 alpha) { - if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) { + if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { const float col[4] = { (float)((color & 0xFF) >> 0) * (1.0f / 255.0f), (float)((color & 0xFF00) >> 8) * (1.0f / 255.0f), diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index efee4d9aa1..334d98e552 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -177,7 +177,7 @@ GPU_Vulkan::~GPU_Vulkan() { void GPU_Vulkan::CheckGPUFeatures() { uint32_t features = 0; - // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. + // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. See #9545 if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || vulkan_->GetPhysicalDeviceProperties().vendorID == VULKAN_VENDOR_AMD) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp index 56711f541a..c758645fc9 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/ext/native/gfx_es2/gpu_features.cpp @@ -64,7 +64,7 @@ void ProcessGPUFeatures() { gl_extensions.bugs |= BUG_FBO_UNUSABLE; } - if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) { + if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { if (!strcmp(gl_extensions.model, "PowerVR SGX 543") || !strcmp(gl_extensions.model, "PowerVR SGX 540") || !strcmp(gl_extensions.model, "PowerVR SGX 530") || @@ -120,9 +120,9 @@ void CheckGLExtensions() { } else if (vendor == "ARM") { gl_extensions.gpuVendor = GPU_VENDOR_ARM; } else if (vendor == "Imagination Technologies") { - gl_extensions.gpuVendor = GPU_VENDOR_POWERVR; + gl_extensions.gpuVendor = GPU_VENDOR_IMGTEC; } else if (vendor == "Qualcomm") { - gl_extensions.gpuVendor = GPU_VENDOR_ADRENO; + gl_extensions.gpuVendor = GPU_VENDOR_QUALCOMM; } else if (vendor == "Broadcom") { gl_extensions.gpuVendor = GPU_VENDOR_BROADCOM; // Just for reference: Galaxy Y has renderer == "VideoCore IV HW" diff --git a/ext/native/gfx_es2/gpu_features.h b/ext/native/gfx_es2/gpu_features.h index 3bc237c3f0..2f405546b8 100644 --- a/ext/native/gfx_es2/gpu_features.h +++ b/ext/native/gfx_es2/gpu_features.h @@ -12,8 +12,8 @@ enum { GPU_VENDOR_AMD = 2, GPU_VENDOR_INTEL = 3, GPU_VENDOR_ARM = 4, // Mali - GPU_VENDOR_POWERVR = 5, - GPU_VENDOR_ADRENO = 6, + GPU_VENDOR_IMGTEC = 5, + GPU_VENDOR_QUALCOMM = 6, GPU_VENDOR_BROADCOM = 7, GPU_VENDOR_UNKNOWN = 0, }; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 9373489833..9671bfa21b 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -250,6 +250,17 @@ enum InfoField { DRIVER, }; +enum class GPUVendor { + UNKNOWN, + NVIDIA, + INTEL, + AMD, + ARM, // Mali + QUALCOMM, + IMGTEC, // PowerVR + BROADCOM, // Raspberry +}; + enum class NativeObject { CONTEXT, CONTEXT_EX, @@ -483,6 +494,7 @@ struct PipelineDesc { }; struct DeviceCaps { + GPUVendor vendor; DataFormat preferredDepthBufferFormat; DataFormat preferredShadowMapFormatLow; DataFormat preferredShadowMapFormatHigh; diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 72e73fe951..b5d53ef930 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -221,6 +221,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferDepthBlitSupported = false; caps_.framebufferDepthCopySupported = true; + D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options)); if (SUCCEEDED(result)) { @@ -241,6 +242,16 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de DXGI_ADAPTER_DESC desc; adapter->GetDesc(&desc); adapterDesc_ = ConvertWStringToUTF8(desc.Description); + switch (desc.VendorId) { + case 0x10DE: caps_.vendor = GPUVendor::NVIDIA; break; + case 0x1002: + case 0x1022: caps_.vendor = GPUVendor::AMD; break; + case 0x163C: + case 0x8086: + case 0x8087: caps_.vendor = GPUVendor::INTEL; break; + default: + caps_.vendor = GPUVendor::UNKNOWN; + } adapter->Release(); } dxgiDevice->Release(); diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 3ac3058575..e2b17b1ce9 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -588,11 +588,23 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) { ELOG("Failed to get adapter identifier: %d", adapterId); } + switch (identifier_.VendorId) { + case 0x10DE: caps_.vendor = GPUVendor::NVIDIA; break; + case 0x1002: + case 0x1022: caps_.vendor = GPUVendor::AMD; break; + case 0x163C: + case 0x8086: + case 0x8087: caps_.vendor = GPUVendor::INTEL; break; + default: + caps_.vendor = GPUVendor::UNKNOWN; + } + if (!FAILED(device->GetDeviceCaps(&d3dCaps_))) { sprintf(shadeLangVersion_, "PS: %04x VS: %04x", d3dCaps_.PixelShaderVersion & 0xFFFF, d3dCaps_.VertexShaderVersion & 0xFFFF); } else { strcpy(shadeLangVersion_, "N/A"); } + caps_.multiViewport = false; caps_.anisoSupported = true; caps_.depthRangeMinusOneToOne = false; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 36532fabe9..c56745899d 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -540,15 +540,15 @@ public: } case VENDORSTRING: return (const char *)glGetString(GL_VENDOR); case VENDOR: - switch (gl_extensions.gpuVendor) { - case GPU_VENDOR_AMD: return "VENDOR_AMD"; - case GPU_VENDOR_POWERVR: return "VENDOR_POWERVR"; - case GPU_VENDOR_NVIDIA: return "VENDOR_NVIDIA"; - case GPU_VENDOR_INTEL: return "VENDOR_INTEL"; - case GPU_VENDOR_ADRENO: return "VENDOR_ADRENO"; - case GPU_VENDOR_ARM: return "VENDOR_ARM"; - case GPU_VENDOR_BROADCOM: return "VENDOR_BROADCOM"; - case GPU_VENDOR_UNKNOWN: + switch (caps_.vendor) { + case GPUVendor::AMD: return "VENDOR_AMD"; + case GPUVendor::IMGTEC: return "VENDOR_POWERVR"; + case GPUVendor::NVIDIA: return "VENDOR_NVIDIA"; + case GPUVendor::INTEL: return "VENDOR_INTEL"; + case GPUVendor::QUALCOMM: return "VENDOR_ADRENO"; + case GPUVendor::ARM: return "VENDOR_ARM"; + case GPUVendor::BROADCOM: return "VENDOR_BROADCOM"; + case GPUVendor::UNKNOWN: default: return "VENDOR_UNKNOWN"; } @@ -603,6 +603,20 @@ OpenGLContext::OpenGLContext() { } caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object; caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; + + switch (gl_extensions.gpuVendor) { + case GPU_VENDOR_AMD: caps_.vendor = GPUVendor::AMD; break; + case GPU_VENDOR_NVIDIA: caps_.vendor = GPUVendor::NVIDIA; break; + case GPU_VENDOR_ARM: caps_.vendor = GPUVendor::ARM; break; + case GPU_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::QUALCOMM; break; + case GPU_VENDOR_BROADCOM: caps_.vendor = GPUVendor::BROADCOM; break; + case GPU_VENDOR_INTEL: caps_.vendor = GPUVendor::INTEL; break; + case GPU_VENDOR_IMGTEC: caps_.vendor = GPUVendor::IMGTEC; break; + case GPU_VENDOR_UNKNOWN: + default: + caps_.vendor = GPUVendor::UNKNOWN; + break; + } } OpenGLContext::~OpenGLContext() { @@ -929,7 +943,7 @@ bool OpenGLContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBit } // Apply the correct alignment. glPixelStorei(GL_PACK_ALIGNMENT, alignment); - if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && gl_extensions.gpuVendor != GPU_VENDOR_NVIDIA)) { + if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && caps_.vendor != GPUVendor::NVIDIA)) { // Some drivers seem to require we specify this. See #8254. glPixelStorei(GL_PACK_ROW_LENGTH, pixelStride); } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 504f900275..1e651b9e1b 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -687,6 +687,17 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. + switch (vulkan->GetPhysicalDeviceProperties().vendorID) { + case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::AMD; break; + case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::ARM; break; + case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::IMGTEC; break; + case VULKAN_VENDOR_NVIDIA: caps_.vendor = GPUVendor::NVIDIA; break; + case VULKAN_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::QUALCOMM; break; + case VULKAN_VENDOR_INTEL: caps_.vendor = GPUVendor::INTEL; break; + default: + caps_.vendor = GPUVendor::UNKNOWN; + } + device_ = vulkan->GetDevice(); queue_ = vulkan->GetGraphicsQueue(); From fde26e947250c67b7e775ef78af6c3dba3cbe882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 16:45:29 +0100 Subject: [PATCH 07/17] Fix gl scissor rect issue. Fixes #10119 --- ext/native/thin3d/thin3d_gl.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 36532fabe9..8156a40b50 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -490,7 +490,12 @@ public: } void SetScissorRect(int left, int top, int width, int height) override { - glScissor(left, targetHeight_ - (top + height), width, height); + int y = top; + if (!curFB_) { + // We render "upside down" to the backbuffer since GL is silly. + y = targetHeight_ - (top + height); + } + glstate.scissorRect.set(left, y, width, height); } void SetViewports(int count, Viewport *viewports) override { @@ -584,6 +589,7 @@ private: int curVBufferOffsets_[4]{}; OpenGLBuffer *curIBuffer_ = nullptr; int curIBufferOffset_ = 0; + OpenGLFramebuffer *curFB_; // Framebuffer state GLuint currentDrawHandle_ = 0; @@ -1680,6 +1686,7 @@ void OpenGLContext::fbo_unbind() { void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) { CHECK_GL_ERROR_IF_DEBUG(); + curFB_ = (OpenGLFramebuffer *)fbo; if (fbo) { OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; // Without FBO_ARB / GLES3, this will collide with bind_for_read, but there's nothing From 2e9d59ad10741d77bb8261b6d024c4b7637e0098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 18:05:25 +0100 Subject: [PATCH 08/17] Android: Use __android_log_assert facility to get pretty message-asserts into crash dumps. --- Common/Log.h | 46 +++++++++++++++++++++++++++++++++++++-- Common/LogManager.cpp | 15 +++++++++++++ Common/MsgHandler.h | 2 +- ext/native/base/logging.h | 2 +- 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/Common/Log.h b/Common/Log.h index 5e45d89c34..2272b8fb38 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -20,7 +20,11 @@ #include #include -#include "MsgHandler.h" +#include "Common/MsgHandler.h" + +#if defined(__ANDROID__) +#include +#endif #define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and debugprintfs from the game itself. #define ERROR_LEVEL 2 // Important errors. @@ -106,6 +110,14 @@ bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type); #define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (false) #define VERBOSE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LVERBOSE, __VA_ARGS__) } while (false) +#if defined(__ANDROID__) + +// Tricky macro to get the basename, that also works if *built* on Win32. +#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : (__builtin_strrchr(__FILE__, '\\') ? __builtin_strrchr(__FILE__, '\\') + 1 : __FILE__)) +void AndroidAssertLog(const char *func, const char *file, int line, const char *condition, const char *fmt, ...); + +#endif + #if MAX_LOGLEVEL >= DEBUG_LEVEL #define _dbg_assert_(_t_, _a_) \ if (!(_a_)) {\ @@ -113,12 +125,27 @@ bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type); __LINE__, __FILE__); \ if (!PanicYesNo("*** Assertion ***\n")) { assert(false); } \ } + +#if defined(__ANDROID__) + +#define _dbg_assert_msg_(_t_, _a_, ...)\ + if (!(_a_)) {\ + printf(__VA_ARGS__); \ + ERROR_LOG(_t_, __VA_ARGS__); \ + if (!PanicYesNo(__VA_ARGS__)) AndroidAssertLog(__FUNCTION__, __FILENAME__, __LINE__, #_a_, __VA_ARGS__); \ + } + +#else // __ANDROID__ + #define _dbg_assert_msg_(_t_, _a_, ...)\ if (!(_a_)) {\ printf(__VA_ARGS__); \ ERROR_LOG(_t_, __VA_ARGS__); \ if (!PanicYesNo(__VA_ARGS__)) { assert(false);} \ } + +#endif // __ANDROID__ + #define _dbg_update_() ; //Host_UpdateLogDisplay(); #else // not debug @@ -131,9 +158,24 @@ bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type); #endif // MAX_LOGLEVEL DEBUG #define _assert_(_a_) \ - _dbg_assert_(SYSTEM, _a_) + if (!(_a_)) {\ + ERROR_LOG(SYSTEM, "Error...\n\n Line: %d\n File: %s\n\nIgnore and continue?", \ + __LINE__, __FILE__); \ + if (!PanicYesNo("*** Assertion ***\n")) { assert(false); } \ + } + +#if defined(__ANDROID__) + +#define _assert_msg_(_t_, _a_, ...) \ + if (!(_a_) && !PanicYesNo(__VA_ARGS__)) { \ + AndroidAssertLog(__FUNCTION__, __FILENAME__, __LINE__, #_a_, __VA_ARGS__); \ + } + +#else // __ANDROID__ #define _assert_msg_(_t_, _a_, ...) \ if (!(_a_) && !PanicYesNo(__VA_ARGS__)) { \ assert(false); \ } + +#endif // __ANDROID__ \ No newline at end of file diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index d5a74ef5e1..57dde3beff 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -57,6 +57,21 @@ bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type) { return false; } +#if defined(__ANDROID__) + +#define LOG_BUF_SIZE 1024 + +void AndroidAssertLog(const char *func, const char *file, int line, const char *condition, const char *fmt, ...) { + char buf[LOG_BUF_SIZE]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + __android_log_assert(condition, "PPSSPP", "%s:%d (%s): [%s] %s", file, line, func, condition, buf); + va_end(args); +} + +#endif + LogManager *LogManager::logManager_ = NULL; struct LogNameTableEntry { diff --git a/Common/MsgHandler.h b/Common/MsgHandler.h index 6dd2d6a4ff..ee28d8ea33 100644 --- a/Common/MsgHandler.h +++ b/Common/MsgHandler.h @@ -25,7 +25,7 @@ enum MSG_TYPE { CRITICAL }; -extern bool MsgAlert(bool yes_no, int Style, const char* format, ...) +bool MsgAlert(bool yes_no, int Style, const char* format, ...) #ifdef __GNUC__ __attribute__((format(printf, 3, 4))) #endif diff --git a/ext/native/base/logging.h b/ext/native/base/logging.h index 4cecf3f8f5..41e6ab519a 100644 --- a/ext/native/base/logging.h +++ b/ext/native/base/logging.h @@ -65,7 +65,7 @@ void OutputDebugStringUTF8(const char *p); #define ILOG(...) __android_log_print(ANDROID_LOG_INFO, APP_NAME, __VA_ARGS__); #define WLOG(...) __android_log_print(ANDROID_LOG_WARN, APP_NAME, __VA_ARGS__); #define ELOG(...) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__); -#define FLOG(...) { __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__); Crash(); } +#define FLOG(...) __android_log_print(ANDROID_LOG_FATAL, APP_NAME, __VA_ARGS__); #define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c)); From acdb89c898c80f56121dc60efe664ae4b1bf15c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Nov 2017 21:00:59 +0100 Subject: [PATCH 09/17] Make our release mode asserts actually fire properly in release mode again... --- Common/Log.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Common/Log.h b/Common/Log.h index 2272b8fb38..bd74c348b5 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -20,6 +20,7 @@ #include #include +#include "CommonFuncs.h" #include "Common/MsgHandler.h" #if defined(__ANDROID__) @@ -123,7 +124,7 @@ void AndroidAssertLog(const char *func, const char *file, int line, const char * if (!(_a_)) {\ ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n\nIgnore and continue?", \ __LINE__, __FILE__); \ - if (!PanicYesNo("*** Assertion ***\n")) { assert(false); } \ + if (!PanicYesNo("*** Assertion ***\n")) { Crash(); } \ } #if defined(__ANDROID__) @@ -141,7 +142,7 @@ void AndroidAssertLog(const char *func, const char *file, int line, const char * if (!(_a_)) {\ printf(__VA_ARGS__); \ ERROR_LOG(_t_, __VA_ARGS__); \ - if (!PanicYesNo(__VA_ARGS__)) { assert(false);} \ + if (!PanicYesNo(__VA_ARGS__)) { Crash();} \ } #endif // __ANDROID__ @@ -161,7 +162,7 @@ void AndroidAssertLog(const char *func, const char *file, int line, const char * if (!(_a_)) {\ ERROR_LOG(SYSTEM, "Error...\n\n Line: %d\n File: %s\n\nIgnore and continue?", \ __LINE__, __FILE__); \ - if (!PanicYesNo("*** Assertion ***\n")) { assert(false); } \ + if (!PanicYesNo("*** Assertion ***\n")) { Crash(); } \ } #if defined(__ANDROID__) @@ -175,7 +176,7 @@ void AndroidAssertLog(const char *func, const char *file, int line, const char * #define _assert_msg_(_t_, _a_, ...) \ if (!(_a_) && !PanicYesNo(__VA_ARGS__)) { \ - assert(false); \ + Crash(); \ } #endif // __ANDROID__ \ No newline at end of file From b6911d27643a374ade97a226dd7ec48d5d320bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 10:46:23 +0100 Subject: [PATCH 10/17] Add a hidden debug option [Graphics]GfxDebugSplitSubmit to try to narrow down some Vulkan issues, see #10163. Also improve some asserts. --- Common/Vulkan/VulkanMemory.cpp | 5 ++-- Core/Config.cpp | 1 + Core/Config.h | 1 + GPU/Vulkan/DrawEngineVulkan.cpp | 5 +--- GPU/Vulkan/PipelineManagerVulkan.cpp | 1 + Windows/GPU/WindowsVulkanContext.cpp | 4 ++- ext/native/thin3d/VulkanRenderManager.cpp | 30 +++++++++++------------ ext/native/thin3d/VulkanRenderManager.h | 5 ++++ ext/native/thin3d/thin3d.h | 2 +- ext/native/thin3d/thin3d_vulkan.cpp | 11 ++++++--- 10 files changed, 38 insertions(+), 27 deletions(-) diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 2538865deb..67d300dc44 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -18,6 +18,7 @@ // Additionally, Common/Vulkan/* , including this file, are also licensed // under the public domain. +#include "Common/Log.h" #include "Common/Vulkan/VulkanMemory.h" VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size) : device_(vulkan->GetDevice()), buf_(0), offset_(0), size_(size), writePtr_(nullptr) { @@ -44,7 +45,7 @@ bool VulkanPushBuffer::AddBuffer() { VkResult res = vkCreateBuffer(device_, &b, nullptr, &info.buffer); if (VK_SUCCESS != res) { - ELOG("vkCreateBuffer failed! result=%d", (int)res); + _assert_msg_(G3D, false, "vkCreateBuffer failed! result=%d", (int)res); return false; } @@ -61,7 +62,7 @@ bool VulkanPushBuffer::AddBuffer() { res = vkAllocateMemory(device_, &alloc, nullptr, &info.deviceMemory); if (VK_SUCCESS != res) { - ELOG("vkAllocateMemory failed! result=%d", (int)res); + _assert_msg_(G3D, false, "vkAllocateMemory failed! size=%d result=%d", (int)reqs.size, (int)res); vkDestroyBuffer(device_, info.buffer, nullptr); return false; } diff --git a/Core/Config.cpp b/Core/Config.cpp index 9e0537ed24..48aee13246 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -545,6 +545,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("FragmentTestCache", &g_Config.bFragmentTestCache, true, true, true), ConfigSetting("GfxDebugOutput", &g_Config.bGfxDebugOutput, false, false, false), + ConfigSetting("GfxDebugSplitSubmit", &g_Config.bGfxDebugSplitSubmit, false, false, false), ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, true, false), ConfigSetting(false), diff --git a/Core/Config.h b/Core/Config.h index ee63af6f30..25882624e3 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -218,6 +218,7 @@ public: bool bHardwareTessellation; std::string sPostShaderName; // Off for off. bool bGfxDebugOutput; + bool bGfxDebugSplitSubmit; // Sound bool bEnableSound; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 88d0ed4b68..5e33cf017f 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -473,7 +473,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView descAlloc.descriptorSetCount = 1; VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); // Even in release mode, this is bad. - _assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d", (int)frame->descSets.size()); + _assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d res=%d", (int)frame->descSets.size(), (int)result); // We just don't write to the slots we don't care about. // We need 8 now that we support secondary texture bindings. @@ -1041,8 +1041,6 @@ DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulka void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) { colStride = 4; - assert(size > 0); - // TODO: This SHOULD work without padding but I can't get it to work on nvidia, so had // to expand to vec4. Driver bug? struct TessData { @@ -1064,6 +1062,5 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po } void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) { - assert(pos); // Nothing to do here! } diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index f63f0de9c1..4f3f8e0552 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -278,6 +278,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip VkPipeline pipeline; VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline); if (result != VK_SUCCESS) { + _assert_msg_(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); return nullptr; } diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index b7a3b44039..e0958b4f7f 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -212,7 +212,9 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m return false; } - draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); + bool splitSubmit = g_Config.bGfxDebugSplitSubmit; + + draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, splitSubmit); bool success = draw_->CreatePresets(); assert(success); // Doesn't fail, we include the compiler. draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 37f2555c09..23f48aba9d 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -762,19 +762,19 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { if (frameData.hasInitCommands) { cmdBufs[numCmdBufs++] = frameData.initCmd; frameData.hasInitCommands = false; - } - if (false) { - // Send the init commands off separately. Used this once to confirm that the cause of a device loss was in the init cmdbuf. - VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = (uint32_t)numCmdBufs; - submit_info.pCommandBuffers = cmdBufs; - res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); - if (res == VK_ERROR_DEVICE_LOST) { - _assert_msg_(G3D, false, "Lost the Vulkan device!"); - } else { - _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed! result=%d", (int)res); + if (splitSubmit_) { + // Send the init commands off separately. Used this once to confirm that the cause of a device loss was in the init cmdbuf. + VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = (uint32_t)numCmdBufs; + submit_info.pCommandBuffers = cmdBufs; + res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); + if (res == VK_ERROR_DEVICE_LOST) { + _assert_msg_(G3D, false, "Lost the Vulkan device!"); + } else { + _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (init)! result=%d", (int)res); + } + numCmdBufs = 0; } - numCmdBufs = 0; } cmdBufs[numCmdBufs++] = frameData.mainCmd; @@ -795,7 +795,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { if (res == VK_ERROR_DEVICE_LOST) { _assert_msg_(G3D, false, "Lost the Vulkan device!"); } else { - _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed! result=%d", (int)res); + _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (main, split=%d)! result=%d", (int)splitSubmit_, (int)res); } // When !triggerFence, we notify after syncing with Vulkan. @@ -823,8 +823,8 @@ void VulkanRenderManager::EndSubmitFrame(int frame) { present.waitSemaphoreCount = 1; VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present); - // TODO: Deal with VK_SUBOPTIMAL_WSI ? - if (res == VK_ERROR_OUT_OF_DATE_KHR) { + // TODO: Deal with VK_SUBOPTIMAL_KHR ? + if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) { // ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain. } else { _assert_msg_(G3D, res == VK_SUCCESS, "vkQueuePresentKHR failed! result=%d", (int)res); diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 86f282d43d..b8257cac86 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -208,6 +208,10 @@ public: return !framebuffers_.empty(); } + void SetSplitSubmit(bool split) { + splitSubmit_ = split; + } + private: bool InitBackbufferFramebuffers(int width, int height); bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. @@ -259,6 +263,7 @@ private: bool insideFrame_ = false; VKRStep *curRenderStep_ = nullptr; std::vector steps_; + bool splitSubmit_ = false; // Execution time state bool run_ = true; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 9671bfa21b..0b77a21641 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -665,7 +665,7 @@ DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapt DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd); #endif -DrawContext *T3DCreateVulkanContext(VulkanContext *context); +DrawContext *T3DCreateVulkanContext(VulkanContext *context, bool split); // UBs for the preset shaders diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 1e651b9e1b..a320a75061 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -22,6 +22,7 @@ #include #include "Common/Vulkan/SPIRVDisasm.h" +#include "Core/Config.h" #include "base/logging.h" #include "base/display.h" @@ -348,7 +349,7 @@ class VKFramebuffer; class VKContext : public DrawContext { public: - VKContext(VulkanContext *vulkan); + VKContext(VulkanContext *vulkan, bool splitSubmit); virtual ~VKContext(); const DeviceCaps &GetDeviceCaps() const override { @@ -674,7 +675,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, const TextureDesc &desc) { return true; } -VKContext::VKContext(VulkanContext *vulkan) +VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) : vulkan_(vulkan), caps_{}, renderManager_(vulkan) { caps_.anisoSupported = vulkan->GetFeaturesAvailable().samplerAnisotropy != 0; caps_.geometryShaderSupported = vulkan->GetFeaturesAvailable().geometryShader != 0; @@ -755,6 +756,8 @@ VKContext::VKContext(VulkanContext *vulkan) assert(VK_SUCCESS == res); pipelineCache_ = vulkan_->CreatePipelineCache(); + + renderManager_.SetSplitSubmit(splitSubmit); } VKContext::~VKContext() { @@ -1188,8 +1191,8 @@ void VKContext::Clear(int clearMask, uint32_t colorval, float depthVal, int sten renderManager_.Clear(colorval, depthVal, stencilVal, mask); } -DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan) { - return new VKContext(vulkan); +DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan, bool split) { + return new VKContext(vulkan, split); } void AddFeature(std::vector &features, const char *name, VkBool32 available, VkBool32 enabled) { From 6f80a164b430802fac218ac8acd83bed8ddedaf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 10:52:57 +0100 Subject: [PATCH 11/17] Allow loading graphics dumps (*.ppdmp) through the regular UI. --- UI/MainScreen.cpp | 4 ++-- Windows/MainWindowMenu.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 66967869b3..e10fd3e1c5 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -527,7 +527,7 @@ void GameBrowser::Refresh() { } } else { std::vector fileInfo; - path_.GetListing(fileInfo, "iso:cso:pbp:elf:prx:"); + path_.GetListing(fileInfo, "iso:cso:pbp:elf:prx:ppdmp:"); for (size_t i = 0; i < fileInfo.size(); i++) { bool isGame = !fileInfo[i].isDirectory; bool isSaveData = false; @@ -971,7 +971,7 @@ bool MainScreen::UseVerticalLayout() const { UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) { #if defined(USING_QT_UI) - QString fileName = QFileDialog::getOpenFileName(NULL, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip)"); + QString fileName = QFileDialog::getOpenFileName(NULL, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip *.ppdmp)"); if (QFile::exists(fileName)) { QDir newPath; g_Config.currentDirectory = newPath.filePath(fileName).toStdString(); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 4764317960..860fabcc07 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -369,7 +369,7 @@ namespace MainWindow { } void BrowseAndBoot(std::string defaultPath, bool browseDirectory) { - static std::wstring filter = L"All supported file types (*.iso *.cso *.pbp *.elf *.prx *.zip)|*.pbp;*.elf;*.iso;*.cso;*.prx;*.zip|PSP ROMs (*.iso *.cso *.pbp *.elf *.prx)|*.pbp;*.elf;*.iso;*.cso;*.prx|Homebrew/Demos installers (*.zip)|*.zip|All files (*.*)|*.*||"; + static std::wstring filter = L"All supported file types (*.iso *.cso *.pbp *.elf *.prx *.zip *.ppdmp)|*.pbp;*.elf;*.iso;*.cso;*.prx;*.zip;*.ppdmp|PSP ROMs (*.iso *.cso *.pbp *.elf *.prx)|*.pbp;*.elf;*.iso;*.cso;*.prx|Homebrew/Demos installers (*.zip)|*.zip|All files (*.*)|*.*||"; for (int i = 0; i < (int)filter.length(); i++) { if (filter[i] == '|') filter[i] = '\0'; From e6be86ce743f5f87097606183d4aa5ca1ccf9a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 11:01:42 +0100 Subject: [PATCH 12/17] ARM buildfix --- GPU/D3D11/GPU_D3D11.cpp | 2 +- GPU/Directx9/GPU_DX9.cpp | 2 +- ext/native/thin3d/thin3d.h | 16 +++++++------- ext/native/thin3d/thin3d_d3d11.cpp | 8 +++---- ext/native/thin3d/thin3d_d3d9.cpp | 8 +++---- ext/native/thin3d/thin3d_gl.cpp | 34 ++++++++++++++--------------- ext/native/thin3d/thin3d_vulkan.cpp | 14 ++++++------ 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 3c8490394b..915121d261 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -208,7 +208,7 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_PREFER_CPU_DOWNLOAD; // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. See #9545 - if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::AMD) { + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::VENDOR_AMD) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; // Breaks text in PaRappa for some reason. } diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 5286e90166..131136ea7c 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -189,7 +189,7 @@ void GPU_DX9::CheckGPUFeatures() { features |= GPU_PREFER_CPU_DOWNLOAD; // Accurate depth is required on AMD so we ignore the compat flag to disable it on those. See #9545 - if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::AMD) { + if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::VENDOR_AMD) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 0b77a21641..16f5493801 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -251,14 +251,14 @@ enum InfoField { }; enum class GPUVendor { - UNKNOWN, - NVIDIA, - INTEL, - AMD, - ARM, // Mali - QUALCOMM, - IMGTEC, // PowerVR - BROADCOM, // Raspberry + VENDOR_UNKNOWN, + VENDOR_NVIDIA, + VENDOR_INTEL, + VENDOR_AMD, + VENDOR_ARM, // Mali + VENDOR_QUALCOMM, + VENDOR_IMGTEC, // PowerVR + VENDOR_BROADCOM, // Raspberry }; enum class NativeObject { diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index b5d53ef930..bd42955300 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -243,14 +243,14 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de adapter->GetDesc(&desc); adapterDesc_ = ConvertWStringToUTF8(desc.Description); switch (desc.VendorId) { - case 0x10DE: caps_.vendor = GPUVendor::NVIDIA; break; + case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; case 0x1002: - case 0x1022: caps_.vendor = GPUVendor::AMD; break; + case 0x1022: caps_.vendor = GPUVendor::VENDOR_AMD; break; case 0x163C: case 0x8086: - case 0x8087: caps_.vendor = GPUVendor::INTEL; break; + case 0x8087: caps_.vendor = GPUVendor::VENDOR_INTEL; break; default: - caps_.vendor = GPUVendor::UNKNOWN; + caps_.vendor = GPUVendor::VENDOR_UNKNOWN; } adapter->Release(); } diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index e2b17b1ce9..f4c0ec8302 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -589,14 +589,14 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID ELOG("Failed to get adapter identifier: %d", adapterId); } switch (identifier_.VendorId) { - case 0x10DE: caps_.vendor = GPUVendor::NVIDIA; break; + case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; case 0x1002: - case 0x1022: caps_.vendor = GPUVendor::AMD; break; + case 0x1022: caps_.vendor = GPUVendor::VENDOR_AMD; break; case 0x163C: case 0x8086: - case 0x8087: caps_.vendor = GPUVendor::INTEL; break; + case 0x8087: caps_.vendor = GPUVendor::VENDOR_INTEL; break; default: - caps_.vendor = GPUVendor::UNKNOWN; + caps_.vendor = GPUVendor::VENDOR_UNKNOWN; } if (!FAILED(device->GetDeviceCaps(&d3dCaps_))) { diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index e71c9f6afb..db6dac8138 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -546,14 +546,14 @@ public: case VENDORSTRING: return (const char *)glGetString(GL_VENDOR); case VENDOR: switch (caps_.vendor) { - case GPUVendor::AMD: return "VENDOR_AMD"; - case GPUVendor::IMGTEC: return "VENDOR_POWERVR"; - case GPUVendor::NVIDIA: return "VENDOR_NVIDIA"; - case GPUVendor::INTEL: return "VENDOR_INTEL"; - case GPUVendor::QUALCOMM: return "VENDOR_ADRENO"; - case GPUVendor::ARM: return "VENDOR_ARM"; - case GPUVendor::BROADCOM: return "VENDOR_BROADCOM"; - case GPUVendor::UNKNOWN: + case GPUVendor::VENDOR_AMD: return "VENDOR_AMD"; + case GPUVendor::VENDOR_IMGTEC: return "VENDOR_POWERVR"; + case GPUVendor::VENDOR_NVIDIA: return "VENDOR_NVIDIA"; + case GPUVendor::VENDOR_INTEL: return "VENDOR_INTEL"; + case GPUVendor::VENDOR_QUALCOMM: return "VENDOR_ADRENO"; + case GPUVendor::VENDOR_ARM: return "VENDOR_ARM"; + case GPUVendor::VENDOR_BROADCOM: return "VENDOR_BROADCOM"; + case GPUVendor::VENDOR_UNKNOWN: default: return "VENDOR_UNKNOWN"; } @@ -611,16 +611,16 @@ OpenGLContext::OpenGLContext() { caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; switch (gl_extensions.gpuVendor) { - case GPU_VENDOR_AMD: caps_.vendor = GPUVendor::AMD; break; - case GPU_VENDOR_NVIDIA: caps_.vendor = GPUVendor::NVIDIA; break; - case GPU_VENDOR_ARM: caps_.vendor = GPUVendor::ARM; break; - case GPU_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::QUALCOMM; break; - case GPU_VENDOR_BROADCOM: caps_.vendor = GPUVendor::BROADCOM; break; - case GPU_VENDOR_INTEL: caps_.vendor = GPUVendor::INTEL; break; - case GPU_VENDOR_IMGTEC: caps_.vendor = GPUVendor::IMGTEC; break; + case GPU_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break; + case GPU_VENDOR_NVIDIA: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; + case GPU_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break; + case GPU_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::VENDOR_QUALCOMM; break; + case GPU_VENDOR_BROADCOM: caps_.vendor = GPUVendor::VENDOR_BROADCOM; break; + case GPU_VENDOR_INTEL: caps_.vendor = GPUVendor::VENDOR_INTEL; break; + case GPU_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break; case GPU_VENDOR_UNKNOWN: default: - caps_.vendor = GPUVendor::UNKNOWN; + caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; } } @@ -949,7 +949,7 @@ bool OpenGLContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBit } // Apply the correct alignment. glPixelStorei(GL_PACK_ALIGNMENT, alignment); - if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && caps_.vendor != GPUVendor::NVIDIA)) { + if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && caps_.vendor != GPUVendor::VENDOR_NVIDIA)) { // Some drivers seem to require we specify this. See #8254. glPixelStorei(GL_PACK_ROW_LENGTH, pixelStride); } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index a320a75061..0044b3f234 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -689,14 +689,14 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. switch (vulkan->GetPhysicalDeviceProperties().vendorID) { - case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::AMD; break; - case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::ARM; break; - case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::IMGTEC; break; - case VULKAN_VENDOR_NVIDIA: caps_.vendor = GPUVendor::NVIDIA; break; - case VULKAN_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::QUALCOMM; break; - case VULKAN_VENDOR_INTEL: caps_.vendor = GPUVendor::INTEL; break; + case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break; + case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break; + case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break; + 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::UNKNOWN; + caps_.vendor = GPUVendor::VENDOR_UNKNOWN; } device_ = vulkan->GetDevice(); From ee759d83e3ae0c4d3413bd109916b6b9e13c95e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 14:42:01 +0100 Subject: [PATCH 13/17] Oops, android buildfix --- android/jni/app-android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 197dfec98d..ddcb32cb09 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -332,7 +332,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, bool success = true; if (g_Vulkan->InitObjects()) { - draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); + draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, g_Config.bGfxDebugSplitSubmit); success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. assert(success); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); From 543bb34dbcd107e7984f9f0b7685a963442d4b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 15:35:01 +0100 Subject: [PATCH 14/17] Yet another buildfix, sorry :/ --- GPU/Vulkan/PipelineManagerVulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 4f3f8e0552..1b27f135b4 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -278,7 +278,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip VkPipeline pipeline; VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline); if (result != VK_SUCCESS) { - _assert_msg_(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + _assert_msg_(G3D, false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); return nullptr; } From 3ecd7b4c0248f1fe428808ab135b2adf032bd7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 22:14:06 +0100 Subject: [PATCH 15/17] Get rid of collision-prone font cache keys. Stress the font cache a little less on slider dialogs. --- ext/native/gfx_es2/draw_text.h | 12 ++++++++++++ ext/native/gfx_es2/draw_text_android.cpp | 23 +++++++++-------------- ext/native/gfx_es2/draw_text_android.h | 5 ++--- ext/native/gfx_es2/draw_text_win.cpp | 23 ++++++++++------------- ext/native/gfx_es2/draw_text_win.h | 5 ++--- ext/native/ui/ui_screen.cpp | 2 ++ ext/native/ui/view.cpp | 8 ++++---- ext/native/ui/view.h | 2 ++ 8 files changed, 43 insertions(+), 37 deletions(-) diff --git a/ext/native/gfx_es2/draw_text.h b/ext/native/gfx_es2/draw_text.h index 482e3912b7..a36db98ad2 100644 --- a/ext/native/gfx_es2/draw_text.h +++ b/ext/native/gfx_es2/draw_text.h @@ -74,6 +74,18 @@ protected: virtual void ClearCache() = 0; void WrapString(std::string &out, const char *str, float maxWidth); + struct CacheKey { + bool operator < (const CacheKey &other) const { + if (fontHash < other.fontHash) + return true; + if (fontHash > other.fontHash) + return false; + return text < other.text; + } + std::string text; + uint32_t fontHash; + }; + int frameCount_; float fontScaleX_; float fontScaleY_; diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/ext/native/gfx_es2/draw_text_android.cpp index c8e7ed1925..922e578a6e 100644 --- a/ext/native/gfx_es2/draw_text_android.cpp +++ b/ext/native/gfx_es2/draw_text_android.cpp @@ -80,11 +80,9 @@ std::string TextDrawerAndroid::NormalizeString(std::string str) { } void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, float *h) { - uint32_t stringHash = hash::Adler32((const uint8_t *)str, len); - uint32_t entryHash = stringHash ^ fontHash_; - + CacheKey key{ std::string(str, len), fontHash_ }; TextMeasureEntry *entry; - auto iter = sizeCache_.find(entryHash); + auto iter = sizeCache_.find(key); if (iter != sizeCache_.end()) { entry = iter->second.get(); } else { @@ -103,7 +101,7 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo entry = new TextMeasureEntry(); entry->width = (size >> 16); entry->height = (size & 0xFFFF); - sizeCache_[entryHash] = std::unique_ptr(entry); + sizeCache_[key] = std::unique_ptr(entry); } entry->lastUsedFrame = frameCount_; *w = entry->width * fontScaleX_ * dpiScale_; @@ -130,11 +128,10 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou float total_w = 0.0f; float total_h = 0.0f; for (size_t i = 0; i < lines.size(); i++) { - uint32_t stringHash = hash::Adler32((const uint8_t *)&lines[i][0], lines[i].length()); - uint32_t entryHash = stringHash ^ fontHash_; + CacheKey key{ lines[i], fontHash_ }; TextMeasureEntry *entry; - auto iter = sizeCache_.find(entryHash); + auto iter = sizeCache_.find(key); if (iter != sizeCache_.end()) { entry = iter->second.get(); } else { @@ -147,7 +144,7 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou entry = new TextMeasureEntry(); entry->width = sizecx; entry->height = sizecy; - sizeCache_[entryHash] = std::unique_ptr(entry); + sizeCache_[key] = std::unique_ptr(entry); } entry->lastUsedFrame = frameCount_; @@ -166,14 +163,12 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, if (text.empty()) return; - uint32_t stringHash = hash::Adler32((const uint8_t *)text.data(), text.size()); - uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24); - + CacheKey key{ std::string(str), fontHash_ }; target.Flush(true); TextStringEntry *entry; - auto iter = cache_.find(entryHash); + auto iter = cache_.find(key); if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; @@ -223,7 +218,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, desc.initData.push_back((uint8_t *)bitmapData); entry->texture = draw_->CreateTexture(desc); delete[] bitmapData; - cache_[entryHash] = std::unique_ptr(entry); + cache_[key] = std::unique_ptr(entry); draw_->BindTexture(0, entry->texture); } float w = entry->bmWidth * fontScaleX_ * dpiScale_; diff --git a/ext/native/gfx_es2/draw_text_android.h b/ext/native/gfx_es2/draw_text_android.h index 010cb8c8b5..9ed3fdbd22 100644 --- a/ext/native/gfx_es2/draw_text_android.h +++ b/ext/native/gfx_es2/draw_text_android.h @@ -44,9 +44,8 @@ private: std::map fontMap_; - // The key is the CityHash of the string xor the fontHash_. - std::map> cache_; - std::map> sizeCache_; + std::map> cache_; + std::map> sizeCache_; }; #endif diff --git a/ext/native/gfx_es2/draw_text_win.cpp b/ext/native/gfx_es2/draw_text_win.cpp index 4f0dd44e19..0b500af293 100644 --- a/ext/native/gfx_es2/draw_text_win.cpp +++ b/ext/native/gfx_es2/draw_text_win.cpp @@ -119,11 +119,10 @@ void TextDrawerWin32::SetFont(uint32_t fontHandle) { } void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float *h) { - uint32_t stringHash = hash::Adler32((const uint8_t *)str, len); - uint32_t entryHash = stringHash ^ fontHash_; - + CacheKey key{ std::string(str, len), fontHash_ }; + TextMeasureEntry *entry; - auto iter = sizeCache_.find(entryHash); + auto iter = sizeCache_.find(key); if (iter != sizeCache_.end()) { entry = iter->second.get(); } else { @@ -139,7 +138,7 @@ void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float entry = new TextMeasureEntry(); entry->width = size.cx; entry->height = size.cy; - sizeCache_[entryHash] = std::unique_ptr(entry); + sizeCache_[key] = std::unique_ptr(entry); } entry->lastUsedFrame = frameCount_; @@ -164,11 +163,10 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound float total_w = 0.0f; float total_h = 0.0f; for (size_t i = 0; i < lines.size(); i++) { - uint32_t stringHash = hash::Adler32((const uint8_t *)&lines[i][0], lines[i].length()); - uint32_t entryHash = stringHash ^ fontHash_; + CacheKey key{ lines[i], fontHash_ }; TextMeasureEntry *entry; - auto iter = sizeCache_.find(entryHash); + auto iter = sizeCache_.find(key); if (iter != sizeCache_.end()) { entry = iter->second.get(); } else { @@ -179,7 +177,7 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound entry = new TextMeasureEntry(); entry->width = size.cx; entry->height = size.cy; - sizeCache_[entryHash] = std::unique_ptr(entry); + sizeCache_[key] = std::unique_ptr(entry); } entry->lastUsedFrame = frameCount_; @@ -197,14 +195,13 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f if (!strlen(str)) return; - uint32_t stringHash = hash::Adler32((const uint8_t *)str, strlen(str)); - uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24); + CacheKey key{ std::string(str), fontHash_ }; target.Flush(true); TextStringEntry *entry; - auto iter = cache_.find(entryHash); + auto iter = cache_.find(key); if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; @@ -304,7 +301,7 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f delete[] bitmapData16; if (bitmapData32) delete[] bitmapData32; - cache_[entryHash] = std::unique_ptr(entry); + cache_[key] = std::unique_ptr(entry); } draw_->BindTexture(0, entry->texture); diff --git a/ext/native/gfx_es2/draw_text_win.h b/ext/native/gfx_es2/draw_text_win.h index a8d35744b5..ec76d3ef2b 100644 --- a/ext/native/gfx_es2/draw_text_win.h +++ b/ext/native/gfx_es2/draw_text_win.h @@ -36,9 +36,8 @@ protected: std::map> fontMap_; uint32_t fontHash_; - // The key is the CityHash of the string xor the fontHash_. - std::map> cache_; - std::map> sizeCache_; + std::map> cache_; + std::map> sizeCache_; }; #endif \ No newline at end of file diff --git a/ext/native/ui/ui_screen.cpp b/ext/native/ui/ui_screen.cpp index a8bb3147bc..a661f6208b 100644 --- a/ext/native/ui/ui_screen.cpp +++ b/ext/native/ui/ui_screen.cpp @@ -638,6 +638,7 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { edit_ = new TextEdit(temp, "", new LinearLayoutParams(10.0f)); edit_->SetMaxLen(16); edit_->SetTextColor(dc.theme->popupStyle.fgColor); + edit_->SetTextAlign(FLAG_DYNAMIC_ASCII); edit_->OnTextChange.Handle(this, &SliderPopupScreen::OnTextChange); changing_ = false; lin->Add(edit_); @@ -668,6 +669,7 @@ void SliderFloatPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { edit_ = new TextEdit(temp, "", new LinearLayoutParams(10.0f)); edit_->SetMaxLen(16); edit_->SetTextColor(dc.theme->popupStyle.fgColor); + edit_->SetTextAlign(FLAG_DYNAMIC_ASCII); edit_->OnTextChange.Handle(this, &SliderFloatPopupScreen::OnTextChange); changing_ = false; lin->Add(edit_); diff --git a/ext/native/ui/view.cpp b/ext/native/ui/view.cpp index 65f1aab6fe..ad977e12da 100644 --- a/ext/native/ui/view.cpp +++ b/ext/native/ui/view.cpp @@ -791,12 +791,12 @@ void TextEdit::Draw(UIContext &dc) { dc.DrawTextRect(placeholderText_.c_str(), bounds_, c, ALIGN_CENTER); } } else { - dc.DrawTextRect(text_.c_str(), textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT); + dc.DrawTextRect(text_.c_str(), textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_); } if (HasFocus()) { // Hack to find the caret position. Might want to find a better way... - dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT); + dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); float caretX = w - scrollPos_; if (caretX > bounds_.w) { scrollPos_ += caretX - bounds_.w; @@ -811,7 +811,7 @@ void TextEdit::Draw(UIContext &dc) { } void TextEdit::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.size() ? text_.c_str() : "Wj", &w, &h); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.size() ? text_.c_str() : "Wj", &w, &h, align_); w += 2; h += 2; } @@ -1115,7 +1115,7 @@ void Slider::Draw(UIContext &dc) { else sprintf(temp, "%i", *value_); dc.SetFontStyle(dc.theme->uiFont); - dc.DrawText(temp, bounds_.x2() - 22, bounds_.centerY(), dc.theme->popupStyle.fgColor, ALIGN_CENTER); + dc.DrawText(temp, bounds_.x2() - 22, bounds_.centerY(), dc.theme->popupStyle.fgColor, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); } void Slider::Update() { diff --git a/ext/native/ui/view.h b/ext/native/ui/view.h index 93afab7c18..a5a0cbac4c 100644 --- a/ext/native/ui/view.h +++ b/ext/native/ui/view.h @@ -784,6 +784,7 @@ public: void SetTextColor(uint32_t color) { textColor_ = color; hasTextColor_ = true; } const std::string &GetText() const { return text_; } void SetMaxLen(size_t maxLen) { maxLen_ = maxLen; } + void SetTextAlign(int align) { align_ = align; } // Only really useful for setting FLAG_DYNAMIC_ASCII void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; void Draw(UIContext &dc) override; @@ -805,6 +806,7 @@ private: int scrollPos_ = 0; size_t maxLen_; bool ctrlDown_ = false; // TODO: Make some global mechanism for this. + int align_ = 0; // TODO: Selections }; From 495532f0ff93f87f4d4715a50808b22e3b3f05e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 22:45:03 +0100 Subject: [PATCH 16/17] Fix text width measurement on Android when there are spaces at the start/end of the string (bounds doesn't handle that). Fixes 10174 --- android/src/org/ppsspp/ppsspp/TextRenderer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/TextRenderer.java b/android/src/org/ppsspp/ppsspp/TextRenderer.java index 587f0e3baa..87a9ca1be3 100644 --- a/android/src/org/ppsspp/ppsspp/TextRenderer.java +++ b/android/src/org/ppsspp/ppsspp/TextRenderer.java @@ -26,10 +26,8 @@ public class TextRenderer { } } private static Point measure(String string, double textSize) { - Rect bound = new Rect(); p.setTextSize((float)textSize); - p.getTextBounds(string, 0, string.length(), bound); - int w = bound.width(); + int w = (int)p.measureText(string); int h = (int)(p.descent() - p.ascent() + 2.0f); // Round width up to even already here to avoid annoyances from odd-width 16-bit textures which // OpenGL does not like - each line must be 4-byte aligned From c04ead1023590ee97c47bd89c81a1bf6e8933b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 23 Nov 2017 15:07:59 +0100 Subject: [PATCH 17/17] When drawing text using our truetype backends, round coordinates to pixels. Fixes #10180 --- ext/native/ui/ui_context.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index fc36b16e9e..c0f4020af1 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -172,7 +172,10 @@ void UIContext::DrawTextRect(const char *str, const Bounds &bounds, uint32_t col Draw()->DrawTextRect(fontStyle_->atlasFont, str, bounds.x, bounds.y, bounds.w, bounds.h, color, align); } else { textDrawer_->SetFontScale(fontScaleX_, fontScaleY_); - textDrawer_->DrawStringRect(*Draw(), str, bounds, color, align); + Bounds rounded = bounds; + rounded.x = floorf(rounded.x); + rounded.y = floorf(rounded.y); + textDrawer_->DrawStringRect(*Draw(), str, rounded, color, align); RebindTexture(); } }