From b87f447e762fbb4a9a456cf6c3e2fc25568294c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 1 Dec 2017 16:53:54 +0100 Subject: [PATCH 01/18] Buildfix, oops --- GPU/Vulkan/FramebufferVulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index b3085ad7c2..018a0ed9b7 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -692,7 +692,7 @@ void FramebufferManagerVulkan::CompilePostShader() { usePostShader_ = true; } else { ELOG("Failed to compile."); - pipelinePostShader_ = nullptr; + pipelinePostShader_ = VK_NULL_HANDLE; usePostShader_ = false; } } From 4049e280a8ca6a6585b68510157a41f181d4bab3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:07:29 -0800 Subject: [PATCH 02/18] Reporting: Disallow feedback for fake game ids. It's just not realistic for everyone to use the same one, which makes the feedback not work well. --- UI/PauseScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index bcb131eb9b..c3b29d2ce3 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -334,7 +334,7 @@ void GamePauseScreen::CreateViews() { // TODO, also might be nice to show overall compat rating here? // Based on their platform or even cpu/gpu/config. Would add an API for it. - if (Reporting::IsSupported() && gameId.size() && gameId != "_") { + if (Reporting::IsSupported() && g_paramSFO.GetValueString("DISC_ID").size()) { I18NCategory *rp = GetI18NCategory("Reporting"); rightColumnItems->Add(new Choice(rp->T("ReportButton", "Report Feedback")))->OnClick.Handle(this, &GamePauseScreen::OnReportFeedback); } From a652617ba0a493ad5b3622b1211797c88c2dc583 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:25:21 -0800 Subject: [PATCH 03/18] Adhoc: Remove incorrect thread create param. This was the options pointer, not the attr, so was always generating an error (which was also reported.) Also, we don't support kernel threads in any real way, so let's just not pass the flag at all. Same behavior as before, less the spurious error. --- Core/HLE/sceNetAdhoc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index c88c888680..7b1f7049a1 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -174,7 +174,7 @@ u32 sceNetAdhocInit() { // TODO: Should use a separated threads for friendFinder, matchingEvent, and matchingInput and created on AdhocctlInit & AdhocMatchingStart instead of here #define PSP_THREAD_ATTR_KERNEL 0x00001000 // PSP_THREAD_ATTR_KERNEL is located in sceKernelThread.cpp instead of sceKernelThread.h :( //threadAdhocID = __KernelCreateThreadInternal("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x30, 4096, PSP_THREAD_ATTR_KERNEL); - threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, 0, PSP_THREAD_ATTR_KERNEL); + threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, 0, 0); if (threadAdhocID > 0) { __KernelStartThread(threadAdhocID, 0, 0); } From 0a365495cd84a543695ddccd61b12d5f0687d259 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:29:17 -0800 Subject: [PATCH 04/18] Reporting: Stop reporting module load versions. We've got plenty of data, don't need to report anymore. --- Core/HLE/sceKernelModule.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 0b5258244c..d76c184188 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1070,9 +1070,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd if (IsHLEVersionedModule(head->modname)) { int ver = (head->module_ver_hi << 8) | head->module_ver_lo; - char temp[256]; - snprintf(temp, sizeof(temp), "Loading module %s with version %%04x, devkit %%08x", head->modname); - INFO_LOG_REPORT(SCEMODULE, temp, ver, head->devkitversion); + INFO_LOG(SCEMODULE, "Loading module %s with version %04x, devkit %08x", head->modname, ver, head->devkitversion); reportedModule = true; if (!strcmp(head->modname, "sceMpeg_library")) { @@ -1434,9 +1432,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd delete [] newptr; if (!reportedModule && IsHLEVersionedModule(modinfo->name)) { - char temp[256]; - snprintf(temp, sizeof(temp), "Loading module %s with version %%04x, devkit %%08x", modinfo->name); - INFO_LOG_REPORT(SCEMODULE, temp, modinfo->moduleVersion, devkitVersion); + INFO_LOG_REPORT(SCEMODULE, "Loading module %s with version %04x, devkit %08x", modinfo->name, modinfo->moduleVersion, devkitVersion); if (!strcmp(modinfo->name, "sceMpeg_library")) { __MpegLoadModule(modinfo->moduleVersion); From d5ae666725d665f4c613635f225e14749cba9caf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:32:23 -0800 Subject: [PATCH 05/18] Reporting: Remove unused code. --- GPU/GPUCommon.cpp | 81 ++--------------------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index fa4fdc3899..983aafe269 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1930,85 +1930,8 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { } void GPUCommon::Execute_Unknown(u32 op, u32 diff) { - switch (op >> 24) { - case GE_CMD_VSCX: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vscx, G3D, "Unsupported Vertex Screen Coordinate X : %06x", op); - break; - - case GE_CMD_VSCY: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vscy, G3D, "Unsupported Vertex Screen Coordinate Y : %06x", op); - break; - - case GE_CMD_VSCZ: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vscz, G3D, "Unsupported Vertex Screen Coordinate Z : %06x", op); - break; - - case GE_CMD_VTCS: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vtcs, G3D, "Unsupported Vertex Texture Coordinate S : %06x", op); - break; - - case GE_CMD_VTCT: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vtct, G3D, "Unsupported Vertex Texture Coordinate T : %06x", op); - break; - - case GE_CMD_VTCQ: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vtcq, G3D, "Unsupported Vertex Texture Coordinate Q : %06x", op); - break; - - case GE_CMD_VCV: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vcv, G3D, "Unsupported Vertex Color Value : %06x", op); - break; - - case GE_CMD_VAP: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vap, G3D, "Unsupported Vertex Alpha and Primitive : %06x", op); - break; - - case GE_CMD_VFC: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vfc, G3D, "Unsupported Vertex Fog Coefficient : %06x", op); - break; - - case GE_CMD_VSCV: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(vscv, G3D, "Unsupported Vertex Secondary Color Value : %06x", op); - break; - - case GE_CMD_UNKNOWN_03: - case GE_CMD_UNKNOWN_0D: - case GE_CMD_UNKNOWN_11: - case GE_CMD_UNKNOWN_29: - case GE_CMD_UNKNOWN_34: - case GE_CMD_UNKNOWN_35: - case GE_CMD_UNKNOWN_39: - case GE_CMD_UNKNOWN_4E: - case GE_CMD_UNKNOWN_4F: - case GE_CMD_UNKNOWN_52: - case GE_CMD_UNKNOWN_59: - case GE_CMD_UNKNOWN_5A: - case GE_CMD_UNKNOWN_B6: - case GE_CMD_UNKNOWN_B7: - case GE_CMD_UNKNOWN_D1: - case GE_CMD_UNKNOWN_ED: - case GE_CMD_UNKNOWN_EF: - case GE_CMD_UNKNOWN_FA: - case GE_CMD_UNKNOWN_FB: - case GE_CMD_UNKNOWN_FC: - case GE_CMD_UNKNOWN_FD: - case GE_CMD_UNKNOWN_FE: - if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(unknowncmd, G3D, "Unknown GE command : %08x ", op); - break; - default: - break; - } + if ((op & 0xFFFFFF) != 0) + WARN_LOG_REPORT_ONCE(unknowncmd, G3D, "Unknown GE command : %08x ", op); } void GPUCommon::FastLoadBoneMatrix(u32 target) { From 0dba5cebb2d5cbfdff21e521ada380f1d47b5d61 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:38:23 -0800 Subject: [PATCH 06/18] Module: Cleanup magic number. --- Core/HLE/sceKernelModule.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index d76c184188..a87bf16d1e 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1808,7 +1808,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { u32 magic; u32 error; std::string error_string; - module = __KernelLoadELFFromPtr(temp, (size_t)size, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); + module = __KernelLoadELFFromPtr(temp, (size_t)size, 0, lmoption ? lmoption->position == PSP_SMEM_High : false, &error_string, &magic, error); delete [] temp; pspFileSystem.CloseFile(handle); @@ -2254,7 +2254,7 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) u8 *temp = new u8[size - pos]; pspFileSystem.ReadFile(handle, temp, size - pos); u32 magic; - module = __KernelLoadELFFromPtr(temp, size - pos, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); + module = __KernelLoadELFFromPtr(temp, size - pos, 0, lmoption ? lmoption->position == PSP_SMEM_High : false, &error_string, &magic, error); delete [] temp; if (!module) { @@ -2311,7 +2311,7 @@ static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, Module *module = 0; u32 magic; u32 error; - module = __KernelLoadELFFromPtr(Memory::GetPointer(bufPtr), size, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); + module = __KernelLoadELFFromPtr(Memory::GetPointer(bufPtr), size, 0, lmoption ? lmoption->position == PSP_SMEM_High : false, &error_string, &magic, error); if (!module) { // Some games try to load strange stuff as PARAM.SFO as modules and expect it to fail. From f9ce1587cbf1bf31c8b56197b6b0598728b67080 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:38:37 -0800 Subject: [PATCH 07/18] Reporting: Skip reporting reused depthbuffers. Basically all games do it, no longer interesting. --- GPU/Common/FramebufferCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 870fa5825a..3a997f59ae 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -484,7 +484,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // This happens a lot, but virtually always it's cleared. // It's possible the other might not clear, but when every game is reported it's not useful. if (params.isWritingDepth) { - WARN_LOG_REPORT(SCEGE, "FBO reusing depthbuffer, %08x/%08x and %08x/%08x", params.fb_address, params.z_address, vfbs_[i]->fb_address, vfbs_[i]->z_address); + WARN_LOG(SCEGE, "FBO reusing depthbuffer, %08x/%08x and %08x/%08x", params.fb_address, params.z_address, vfbs_[i]->fb_address, vfbs_[i]->z_address); sharingReported = true; } } From db300da1d7a329408601e4aebf5a7b7232994cd2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:45:58 -0800 Subject: [PATCH 08/18] Reporting: Improve no pos verts message. --- GPU/Common/VertexDecoderCommon.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 4cd6f9e40d..4cf4d37287 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -1125,8 +1125,9 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, decOff += DecFmtSize(decFmt.nrmfmt); } + bool reportNoPos = false; if (!pos) { - ERROR_LOG_REPORT(G3D, "Vertices without position found"); + reportNoPos = true; pos = 1; } if (pos) { // there's always a position @@ -1161,6 +1162,12 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, size *= morphcount; DEBUG_LOG(G3D, "SVT : size = %i, aligned to biggest %i", size, biggest); + if (reportNoPos) { + char temp[256]{}; + ToString(temp); + ERROR_LOG_REPORT(G3D, "Vertices without position found: (%08x) %s", fmt_, temp); + } + // Attempt to JIT as well. But only do that if the main CPU JIT is enabled, in order to aid // debugging attempts - if the main JIT doesn't work, this one won't do any better, probably. if (jitCache && g_Config.bVertexDecoderJit && g_Config.iCpuCore == (int)CPUCore::JIT) { From 04515946e621ed9723a3a4f91eb53ff731718433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 1 Dec 2017 17:45:43 +0100 Subject: [PATCH 09/18] Comment, minor cleanup --- android/src/org/ppsspp/ppsspp/NativeActivity.java | 2 ++ ext/native/ui/screen.cpp | 2 +- ext/native/ui/screen.h | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 78db54746d..1eea8c70f9 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -661,6 +661,8 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C mSurfaceView.onDestroy(); mSurfaceView = null; } + // TODO: Can we ensure that the GL thread has stopped rendering here? + // I've seen crashes that seem to indicate that sometimes it hasn't... NativeApp.audioShutdown(); if (shuttingDown || isFinishing()) { unregisterCallbacks(); diff --git a/ext/native/ui/screen.cpp b/ext/native/ui/screen.cpp index 45e06ef3e4..73a5dc38c0 100644 --- a/ext/native/ui/screen.cpp +++ b/ext/native/ui/screen.cpp @@ -181,7 +181,7 @@ void ScreenManager::shutdown() { delete x->screen; stack_.clear(); delete nextScreen_; - nextScreen_ = 0; + nextScreen_ = nullptr; } void ScreenManager::push(Screen *screen, int layerFlags) { diff --git a/ext/native/ui/screen.h b/ext/native/ui/screen.h index a593ef8c1a..ee8093d054 100644 --- a/ext/native/ui/screen.h +++ b/ext/native/ui/screen.h @@ -42,9 +42,9 @@ namespace Draw { class Screen { public: - Screen() : screenManager_(0) { } + Screen() : screenManager_(nullptr) { } virtual ~Screen() { - screenManager_ = 0; + screenManager_ = nullptr; } virtual void onFinish(DialogResult reason) {} From 46ffa8cc0baab47b73004571271dd1d09480adb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 1 Dec 2017 17:46:02 +0100 Subject: [PATCH 10/18] Try to help Mali 400 shader reg alloc by reusing variables. It's still commonly reported. --- GPU/GLES/VertexShaderGeneratorGLES.cpp | 30 +++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index c974af4a1f..c1348bd9ad 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -697,7 +697,7 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, bool diffuseIsZero = true; bool specularIsZero = true; bool distanceNeeded = false; - + bool anySpots = false; if (enableLighting) { WRITE(p, " lowp vec4 lightSum0 = u_ambient * %s + vec4(u_matemissive, 0.0);\n", ambientStr); @@ -711,6 +711,8 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, specularIsZero = false; if (type != GE_LIGHTTYPE_DIRECTIONAL) distanceNeeded = true; + if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) + anySpots = true; } if (!specularIsZero) { @@ -724,6 +726,10 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " float distance;\n"); WRITE(p, " lowp float lightScale;\n"); } + WRITE(p, " mediump float ldot;\n"); + if (anySpots) { + WRITE(p, " lowp float angle;\n"); + } } // Calculate lights if needed. If shade mapping is enabled, lights may need to be @@ -747,14 +753,14 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE; bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; - WRITE(p, " mediump float dot%i = max(dot(toLight, worldnormal), 0.0);\n", i); + WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n"); if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) - WRITE(p, " if (dot%i == 0.0 && u_matspecular.a == 0.0) {\n", i); - WRITE(p, " dot%i = 1.0;\n", i); + WRITE(p, " if (ldot == 0.0 && u_matspecular.a == 0.0) {\n"); + WRITE(p, " ldot = 1.0;\n"); WRITE(p, " } else {\n"); - WRITE(p, " dot%i = pow(dot%i, u_matspecular.a);\n", i, i); + WRITE(p, " ldot = pow(ldot, u_matspecular.a);\n"); WRITE(p, " }\n"); } @@ -770,9 +776,9 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: - WRITE(p, " lowp float angle%i = dot(normalize(u_lightdir%i), toLight);\n", i, i); - WRITE(p, " if (angle%i >= u_lightangle%i) {\n", i, i); - WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle%i, u_lightspotCoef%i);\n", i, i, i); + WRITE(p, " angle = dot(normalize(u_lightdir%i), toLight);\n", i); + WRITE(p, " if (angle >= u_lightangle%i) {\n", i); + WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle, u_lightspotCoef%i);\n", i, i); WRITE(p, " } else {\n"); WRITE(p, " lightScale = 0.0;\n"); WRITE(p, " }\n"); @@ -782,11 +788,11 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, break; } - WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * dot%i;\n", i, diffuseStr, i); + WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * ldot;\n", i, diffuseStr); if (doSpecular) { - WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i); - WRITE(p, " if (dot%i > 0.0)\n", i); - WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(dot%i, u_matspecular.a) %s);\n", i, specularStr, i, timesLightScale); + WRITE(p, " ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); + WRITE(p, " if (ldot > 0.0)\n"); + WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); } WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); } From a0e4b6ad0b1eef2396d8a0d412f7da8d7875ca6d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 09:50:31 -0800 Subject: [PATCH 11/18] Reporting: Improve bezier/spline morph/skin data. Most of these are probably garbage? --- GPU/GPUCommon.cpp | 7 ++----- GPU/Software/SoftGpu.cpp | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 983aafe269..8ed6a970c3 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1394,11 +1394,8 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); } - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); + if ((gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) || vertTypeIsSkinningEnabled(gstate.vertType)) { + DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 67f929cdf0..c9d8c50bac 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -395,11 +395,8 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) { indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); } - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); + if ((gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) || vertTypeIsSkinningEnabled(gstate.vertType)) { + DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); From 786a3ae17c21ad064514890199052eecfd44f5d4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 10:06:06 -0800 Subject: [PATCH 12/18] Reporting: Don't report with locked CPU speed. --- Core/Reporting.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 8f1fd199a9..1dbc95c062 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -457,8 +457,7 @@ namespace Reporting return false; if (CheatsInEffect()) return false; - // Not sure if we should support locked cpu at all, but definitely not far out values. - if (g_Config.iLockedCPUSpeed != 0 && (g_Config.iLockedCPUSpeed < 111 || g_Config.iLockedCPUSpeed > 333)) + if (g_Config.iLockedCPUSpeed != 0) return false; // Don't allow builds without version info from git. They're useless for reporting. if (strcmp(PPSSPP_GIT_VERSION, "unknown") == 0) From 5fbbb3e115c23e46bb6b533cc0de709f86bbbaf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 1 Dec 2017 19:55:55 +0100 Subject: [PATCH 13/18] Try a silly workaround for an otherwise unexplainable crash seen in Google Play Console --- android/src/org/ppsspp/ppsspp/NativeActivity.java | 11 +++++++++++ android/src/org/ppsspp/ppsspp/NativeApp.java | 1 - android/src/org/ppsspp/ppsspp/NativeRenderer.java | 7 +++++++ ext/native/thin3d/VulkanQueueRunner.cpp | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 1eea8c70f9..5601a8462d 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -651,6 +651,17 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C protected void onDestroy() { super.onDestroy(); if (javaGL) { + if (nativeRenderer.isRenderingFrame()) { + Log.i(TAG, "Waiting for renderer to finish."); + int tries = 200; + do { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + tries--; + } while (nativeRenderer.isRenderingFrame() && tries > 0); + } Log.i(TAG, "onDestroy"); mGLSurfaceView.onDestroy(); // Probably vain attempt to help the garbage collector... diff --git a/android/src/org/ppsspp/ppsspp/NativeApp.java b/android/src/org/ppsspp/ppsspp/NativeApp.java index 4ec90e6fc9..dd78133e0c 100644 --- a/android/src/org/ppsspp/ppsspp/NativeApp.java +++ b/android/src/org/ppsspp/ppsspp/NativeApp.java @@ -32,7 +32,6 @@ public class NativeApp { public static native void pause(); public static native void resume(); - // There's not really any reason to ever call shutdown as we can recover from a killed activity. public static native void shutdown(); public static native boolean keyDown(int deviceId, int key, boolean isRepeat); diff --git a/android/src/org/ppsspp/ppsspp/NativeRenderer.java b/android/src/org/ppsspp/ppsspp/NativeRenderer.java index 87191e8089..288beba61a 100644 --- a/android/src/org/ppsspp/ppsspp/NativeRenderer.java +++ b/android/src/org/ppsspp/ppsspp/NativeRenderer.java @@ -13,13 +13,20 @@ import android.view.Display; public class NativeRenderer implements GLSurfaceView.Renderer { private static String TAG = "NativeRenderer"; private NativeActivity mActivity; + private boolean inFrame; NativeRenderer(NativeActivity act) { mActivity = act; } + public boolean isRenderingFrame() { + return inFrame; + } + public void onDrawFrame(GL10 unused /*use GLES20*/) { + inFrame = true; displayRender(); + inFrame = false; } public void onSurfaceCreated(GL10 unused, EGLConfig config) { diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index e49ff6bd4c..59937c9d39 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -2,7 +2,7 @@ #include "VulkanQueueRunner.h" #include "VulkanRenderManager.h" -// Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP +// Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP NativeGLView NativeRenderer NativeSurfaceView PowerSaveModeReceiver InputDeviceState void VulkanQueueRunner::CreateDeviceObjects() { ILOG("VulkanQueueRunner::CreateDeviceObjects"); From 6eb8630526e22b034ca96b23dec67fd8ac145ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 1 Dec 2017 20:01:13 +0100 Subject: [PATCH 14/18] Improve reporting for imm buffer exceeded. Reset the immCount_ every frame to avoid getting "stuck" permanently in case some garbage is executed.. --- GPU/GPUCommon.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 8ed6a970c3..540dd80d6a 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -917,6 +917,7 @@ bool GPUCommon::InterpretList(DisplayList &list) { } void GPUCommon::BeginFrame() { + immCount_ = 0; if (dumpNextFrame_) { NOTICE_LOG(G3D, "DUMPING THIS FRAME"); dumpThisFrame_ = true; @@ -1810,7 +1811,7 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { if (immCount_ >= MAX_IMMBUFFER_SIZE) { // Only print once for each overrun. if (immCount_ == MAX_IMMBUFFER_SIZE) { - ERROR_LOG_REPORT_ONCE(exceed_imm_buffer, G3D, "Exceeded immediate draw buffer size"); + ERROR_LOG_REPORT_ONCE(exceed_imm_buffer, G3D, "Exceeded immediate draw buffer size. gstate.imm_ap=%06x , prim=%d", gstate.imm_ap & 0xFFFFFF, (int)immPrim_); } if (immCount_ < 0x7fffffff) // Paranoia :) immCount_++; From be6343612f7c4d92caae8c618ddfe028b46be847 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 11:17:12 -0800 Subject: [PATCH 15/18] GPU: Add missing shader id to short desc. --- GPU/Common/ShaderId.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 6329103da4..88f76da774 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -22,7 +22,11 @@ std::string VertexShaderDesc(const ShaderID &id) { if (id.Bit(VS_BIT_ENABLE_FOG)) desc << "Fog "; if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN "; if (id.Bit(VS_BIT_DO_TEXTURE)) desc << "Tex "; - if (id.Bit(VS_BIT_DO_TEXTURE_TRANSFORM)) desc << "TexProj "; + if (id.Bit(VS_BIT_DO_TEXTURE_TRANSFORM)) { + int uvprojMode = id.Bits(VS_BIT_UVPROJ_MODE, 2); + const char *uvprojModes[4] = { "TexProjPos ", "TexProjUV ", "TexProjNNrm ", "TexProjNrm " }; + desc << uvprojModes[uvprojMode]; + } int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2); const char *uvgModes[4] = { "UV ", "UVMtx ", "UVEnv ", "UVUnk " }; int ls0 = id.Bits(VS_BIT_LS0, 2); @@ -51,8 +55,6 @@ std::string VertexShaderDesc(const ShaderID &id) { if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT "; if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN "; - // TODO: More... - return desc.str(); } From 2a540de329120eaf3eed7c91dd7f07695cb78585 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 11:17:51 -0800 Subject: [PATCH 16/18] Reporting: Use a different link message on preload. May help us determine if this only happens from a corrupt cache. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 12 ++++++++---- GPU/GLES/ShaderManagerGLES.h | 6 +++--- GPU/GLES/VertexShaderGeneratorGLES.cpp | 2 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 2a32a3ca4f..cfeed7bb19 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -60,7 +60,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l const u32 vertType = gstate.vertType; bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); - bool lmode = id.Bit(VS_BIT_LMODE) && !isModeThrough; // TODO: Different expression than in shaderIDgen + bool lmode = id.Bit(VS_BIT_LMODE); bool doTexture = id.Bit(VS_BIT_DO_TEXTURE); bool doTextureTransform = id.Bit(VS_BIT_DO_TEXTURE_TRANSFORM); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index a9e856348c..a0d127d36e 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -92,8 +92,8 @@ Shader::~Shader() { glDeleteShader(shader); } -LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, bool useHWTransform) - : useHWTransform_(useHWTransform), program(0), dirtyUniforms(0) { +LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, bool useHWTransform, bool preloading) + : useHWTransform_(useHWTransform) { PROFILE_THIS_SCOPE("shaderlink"); program = glCreateProgram(); @@ -153,7 +153,11 @@ LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, ERROR_LOG(G3D, "FS desc:\n%s", fs_desc.c_str()); ERROR_LOG(G3D, "VS:\n%s\n", vs_source.c_str()); ERROR_LOG(G3D, "FS:\n%s\n", fs_source.c_str()); - Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", buf, fs_desc.c_str(), fs_source.c_str(), vs_desc.c_str(), vs_source.c_str()); + if (preloading) { + Reporting::ReportMessage("Error in shader program link during preload: info: %s\nfs: %s\n%s\nvs: %s\n%s", buf, fs_desc.c_str(), fs_source.c_str(), vs_desc.c_str(), vs_source.c_str()); + } else { + Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", buf, fs_desc.c_str(), fs_source.c_str(), vs_desc.c_str(), vs_source.c_str()); + } #ifdef SHADERLOG OutputDebugStringUTF8(buf); OutputDebugStringUTF8(vs_source.c_str()); @@ -1011,7 +1015,7 @@ void ShaderManagerGLES::LoadAndPrecompile(const std::string &filename) { Shader *vs = vsCache_.Get(vsid); Shader *fs = fsCache_.Get(fsid); if (vs && fs) { - LinkedShader *ls = new LinkedShader(vsid, vs, fsid, fs, vs->UseHWTransform()); + LinkedShader *ls = new LinkedShader(vsid, vs, fsid, fs, vs->UseHWTransform(), true); LinkedShaderCacheEntry entry(vs, fs, ls); linkedShaderCache_.push_back(entry); } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 4e06d31803..a98ed702c4 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -43,7 +43,7 @@ enum { class LinkedShader { public: - LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, bool useHWTransform); + LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, bool useHWTransform, bool preloading = false); ~LinkedShader(); void use(const ShaderID &VSID, LinkedShader *previous); @@ -54,9 +54,9 @@ public: // Set to false if the VS failed, happens on Mali-400 a lot for complex shaders. bool useHWTransform_; - uint32_t program; + uint32_t program = 0; uint64_t availableUniforms; - uint64_t dirtyUniforms; + uint64_t dirtyUniforms = 0; // Present attributes in the shader. int attrMask; // 1 << ATTR_ ... or-ed together. diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index c974af4a1f..7bc319a77d 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -165,7 +165,7 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, } bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); - bool lmode = id.Bit(VS_BIT_LMODE) && !isModeThrough; // TODO: Different expression than in shaderIDgen + bool lmode = id.Bit(VS_BIT_LMODE); bool doTexture = id.Bit(VS_BIT_DO_TEXTURE); bool doTextureProjection = id.Bit(VS_BIT_DO_TEXTURE_TRANSFORM); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 1a80625422..13cb2e307f 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -106,7 +106,7 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses bool highpTexcoord = false; bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); - bool lmode = id.Bit(VS_BIT_LMODE) && !isModeThrough; // TODO: Different expression than in shaderIDgen + bool lmode = id.Bit(VS_BIT_LMODE); bool doTexture = id.Bit(VS_BIT_DO_TEXTURE); bool doTextureTransform = id.Bit(VS_BIT_DO_TEXTURE_TRANSFORM); From d551c9e741c520f5e8d468f022266982eefd4911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 1 Dec 2017 23:11:15 +0100 Subject: [PATCH 17/18] Add a github issue template. Let's see if this works. https://github.com/blog/2111-issue-and-pull-request-templates --- .github/ISSUE_TEMPLATE | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE new file mode 100644 index 0000000000..d3066ebf29 --- /dev/null +++ b/.github/ISSUE_TEMPLATE @@ -0,0 +1,13 @@ +What happens? + + + +What *should* happen? + + + + +What hardware and operating system are you running PPSSPP on? GPU might matter if it's a graphical issue. + + + From 7fd91ffe8524364c36053b92954fd6b2548ae831 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 1 Dec 2017 16:21:34 -0800 Subject: [PATCH 18/18] Display: Correct max FPS limiting skew. We were letting a percentage of too frequent flips through, causing sometimes much higher FPS still. Improves performance in GoW. --- Core/HLE/sceDisplay.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index b0a352b6cf..c94aedc84b 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -157,9 +157,10 @@ static float flips = 0.0f; static int actualFlips = 0; // taking frameskip into account static int lastActualFlips = 0; static float actualFps = 0; -static u64 lastFlipCycles = 0; // For the "max 60 fps" setting. static int lastFlipsTooFrequent = 0; +static u64 lastFlipCycles = 0; +static u64 nextFlipCycles = 0; void hleEnterVblank(u64 userdata, int cyclesLate); void hleLeaveVblank(u64 userdata, int cyclesLate); @@ -196,8 +197,9 @@ void __DisplayInit() { framebuf.fmt = GE_FORMAT_8888; framebuf.stride = 512; memcpy(&latchedFramebuf, &framebuf, sizeof(latchedFramebuf)); - lastFlipCycles = 0; lastFlipsTooFrequent = 0; + lastFlipCycles = 0; + nextFlipCycles = 0; wasPaused = false; enterVblankEvent = CoreTiming::RegisterEvent("EnterVBlank", &hleEnterVblank); @@ -876,27 +878,32 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) s64 delayCycles = 0; // Don't count transitions between display off and display on. if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && g_Config.iForceMaxEmulatedFPS > 0) { - // Sometimes we get a small number, there's probably no need to delay the thread for this. // sceDisplaySetFramebuf() isn't supposed to delay threads at all. This is a hack. - const int FLIP_DELAY_CYCLES_MIN = 10; + // So let's only delay when it's more than 1ms. + const s64 FLIP_DELAY_CYCLES_MIN = usToCycles(1000); // Some games (like Final Fantasy 4) only call this too much in spurts. // The goal is to fix games where this would result in a consistent overhead. const int FLIP_DELAY_MIN_FLIPS = 30; + // Since we move nextFlipCycles forward a whole frame each time, we allow it to be a little ahead. + // Otherwise it'll always be ahead if the game messes up even once. + const s64 LEEWAY_CYCLES_PER_FLIP = usToCycles(10); u64 now = CoreTiming::GetTicks(); - // 1001 to account for NTSC timing (59.94 fps.) - u64 expected = msToCycles(1001) / g_Config.iForceMaxEmulatedFPS; - u64 actual = now - lastFlipCycles; - if (actual < expected - FLIP_DELAY_CYCLES_MIN) { + s64 cyclesAhead = nextFlipCycles - now; + if (cyclesAhead > FLIP_DELAY_CYCLES_MIN) { if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS) { - delayCycles = expected - actual; + delayCycles = cyclesAhead; } else { ++lastFlipsTooFrequent; } - } else { + } else if (-lastFlipsTooFrequent < FLIP_DELAY_MIN_FLIPS) { --lastFlipsTooFrequent; } - lastFlipCycles = CoreTiming::GetTicks(); + + // 1001 to account for NTSC timing (59.94 fps.) + u64 expected = msToCycles(1001) / g_Config.iForceMaxEmulatedFPS - LEEWAY_CYCLES_PER_FLIP; + lastFlipCycles = now; + nextFlipCycles = std::max(lastFlipCycles, nextFlipCycles) + expected; } __DisplaySetFramebuf(topaddr, linesize, pixelformat, sync);