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. + + + diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 9c1d24b45f..bdd6fd2a5e 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -158,9 +158,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); @@ -200,8 +201,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); @@ -893,27 +895,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); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 0b5258244c..a87bf16d1e 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); @@ -1812,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); @@ -2258,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) { @@ -2315,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. diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index a0f387f837..3a35b7fa5d 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); } 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) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 3b4020e6b1..1b314261c0 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -487,7 +487,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; } } diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index df140be611..3a8f0de37e 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(); } 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) { diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 4670584cb0..1540061ca6 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -88,7 +88,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 fc1bda1304..eae0c48481 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -93,8 +93,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(); @@ -154,7 +154,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()); @@ -1030,7 +1034,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 94b19554d4..f95e066dde 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 f5e7ce8c49..96406f709c 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -173,7 +173,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); @@ -716,7 +716,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); @@ -730,6 +730,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) { @@ -743,6 +745,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 @@ -766,14 +772,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"); } @@ -789,9 +795,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"); @@ -801,11 +807,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); } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6e4514965e..3caa4b0731 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -923,6 +923,7 @@ bool GPUCommon::InterpretList(DisplayList &list) { } void GPUCommon::BeginFrame() { + immCount_ = 0; if (dumpNextFrame_) { NOTICE_LOG(G3D, "DUMPING THIS FRAME"); dumpThisFrame_ = true; @@ -1400,11 +1401,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(); @@ -1819,7 +1817,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_++; @@ -1936,85 +1934,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) { 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(); 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; } } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 8b5e746187..1ce4db4169 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -110,7 +110,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); diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index d871a78767..5a11268765 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); } diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 78db54746d..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... @@ -661,6 +672,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/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"); 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) {}