Introduce "Compatibility Flags".
These should be used very restrictively, see comment in Compatibility.h. Should help #8004, by disabling depth rounding in Fight Night round 3.
This commit is contained in:
parent
c6789c28f9
commit
b07b002040
16 changed files with 182 additions and 13 deletions
|
@ -1132,6 +1132,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||||
Core/Config.h
|
Core/Config.h
|
||||||
Core/Core.cpp
|
Core/Core.cpp
|
||||||
Core/Core.h
|
Core/Core.h
|
||||||
|
Core/Compatibility.cpp
|
||||||
|
Core/Compatibility.h
|
||||||
Core/CoreParameter.h
|
Core/CoreParameter.h
|
||||||
Core/CoreTiming.cpp
|
Core/CoreTiming.cpp
|
||||||
Core/CoreTiming.h
|
Core/CoreTiming.h
|
||||||
|
|
43
Core/Compatibility.cpp
Normal file
43
Core/Compatibility.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright (c) 2013- PPSSPP Project.
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, version 2.0 or later versions.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
|
// Official git repository and contact information can be found at
|
||||||
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||||
|
|
||||||
|
#include "file/ini_file.h"
|
||||||
|
#include "Core/Compatibility.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
|
void Compatibility::Load(const std::string &gameID) {
|
||||||
|
IniFile compat;
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
std::string path = GetSysDirectory(DIRECTORY_SYSTEM) + "compat.ini";
|
||||||
|
if (compat.Load(path)) {
|
||||||
|
LoadIniSection(compat, gameID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This loads from assets.
|
||||||
|
if (compat.LoadFromVFS("compat.ini")) {
|
||||||
|
LoadIniSection(compat, gameID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compatibility::Clear() {
|
||||||
|
memset(&flags_, 0, sizeof(flags_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compatibility::LoadIniSection(IniFile &iniFile, std::string section) {
|
||||||
|
iniFile.Get(section.c_str(), "NoDepthRounding", &flags_.NoDepthRounding, flags_.NoDepthRounding);
|
||||||
|
}
|
70
Core/Compatibility.h
Normal file
70
Core/Compatibility.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (c) 2015- PPSSPP Project.
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, version 2.0 or later versions.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
|
// Official git repository and contact information can be found at
|
||||||
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Compatibility flags are controlled by assets/compat.ini.
|
||||||
|
// Alternatively, if PSP/SYSTEM/compat.ini exists, it is merged on top, to enable editing
|
||||||
|
// the file on Android for tests.
|
||||||
|
//
|
||||||
|
// This file is not meant to be user-editable, although is kept as a separate ini
|
||||||
|
// file instead of compiled into the code for debugging purposes.
|
||||||
|
//
|
||||||
|
// The uses cases are strict:
|
||||||
|
// * Enable fixes for things we can't reasonably emulate without completely ruining
|
||||||
|
// performance for other games, such as the screen copies in Dangan Ronpa
|
||||||
|
// * Disabling accuracy features like 16-bit depth rounding, when we can't seem to
|
||||||
|
// implement them at all in a 100% compatible way
|
||||||
|
// * Emergency game-specific compatibility fixes before releases, such as the GTA
|
||||||
|
// music problem where every attempted fix has reduced compatibility with other games
|
||||||
|
// * Enable "unsafe" performance optimizations that some games can tolerate and
|
||||||
|
// others cannot. We do not currently have any of those.
|
||||||
|
//
|
||||||
|
// This functionality should NOT be used for any of the following:
|
||||||
|
// * Cheats
|
||||||
|
// * Fun hacks, like enlarged heads or whatever
|
||||||
|
// * Fixing general compatibility issues. First try to find a general solution. Try hard.
|
||||||
|
//
|
||||||
|
// We already have the Action Replay-based cheat system for such use cases.
|
||||||
|
|
||||||
|
struct CompatFlags {
|
||||||
|
bool NoDepthRounding;
|
||||||
|
// GTAMusicFix, ...
|
||||||
|
};
|
||||||
|
|
||||||
|
class IniFile;
|
||||||
|
|
||||||
|
class Compatibility {
|
||||||
|
public:
|
||||||
|
Compatibility() {
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags enforced read-only through const. Only way to change them is to load assets/compat.ini.
|
||||||
|
const CompatFlags &flags() const { return flags_; }
|
||||||
|
|
||||||
|
void Load(const std::string &gameID);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Clear();
|
||||||
|
void LoadIniSection(IniFile &iniFile, std::string section);
|
||||||
|
|
||||||
|
CompatFlags flags_;
|
||||||
|
};
|
|
@ -179,6 +179,7 @@
|
||||||
<ClCompile Include="..\ext\udis86\syn-intel.c" />
|
<ClCompile Include="..\ext\udis86\syn-intel.c" />
|
||||||
<ClCompile Include="..\ext\udis86\syn.c" />
|
<ClCompile Include="..\ext\udis86\syn.c" />
|
||||||
<ClCompile Include="..\ext\udis86\udis86.c" />
|
<ClCompile Include="..\ext\udis86\udis86.c" />
|
||||||
|
<ClCompile Include="Compatibility.cpp" />
|
||||||
<ClCompile Include="Config.cpp" />
|
<ClCompile Include="Config.cpp" />
|
||||||
<ClCompile Include="Core.cpp" />
|
<ClCompile Include="Core.cpp" />
|
||||||
<ClCompile Include="CoreTiming.cpp" />
|
<ClCompile Include="CoreTiming.cpp" />
|
||||||
|
@ -501,6 +502,7 @@
|
||||||
<ClInclude Include="..\ext\udis86\types.h" />
|
<ClInclude Include="..\ext\udis86\types.h" />
|
||||||
<ClInclude Include="..\ext\udis86\udint.h" />
|
<ClInclude Include="..\ext\udis86\udint.h" />
|
||||||
<ClInclude Include="..\ext\udis86\udis86.h" />
|
<ClInclude Include="..\ext\udis86\udis86.h" />
|
||||||
|
<ClInclude Include="Compatibility.h" />
|
||||||
<ClInclude Include="Config.h" />
|
<ClInclude Include="Config.h" />
|
||||||
<ClInclude Include="Core.h" />
|
<ClInclude Include="Core.h" />
|
||||||
<ClInclude Include="CoreParameter.h" />
|
<ClInclude Include="CoreParameter.h" />
|
||||||
|
|
|
@ -622,6 +622,9 @@
|
||||||
<ClCompile Include="FileLoaders\DiskCachingFileLoader.cpp">
|
<ClCompile Include="FileLoaders\DiskCachingFileLoader.cpp">
|
||||||
<Filter>FileLoaders</Filter>
|
<Filter>FileLoaders</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Compatibility.cpp">
|
||||||
|
<Filter>Core</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="ELF\ElfReader.h">
|
<ClInclude Include="ELF\ElfReader.h">
|
||||||
|
@ -1167,6 +1170,9 @@
|
||||||
<ClInclude Include="HLE\ThreadQueueList.h">
|
<ClInclude Include="HLE\ThreadQueueList.h">
|
||||||
<Filter>HLE</Filter>
|
<Filter>HLE</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Compatibility.h">
|
||||||
|
<Filter>Core</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="CMakeLists.txt" />
|
<None Include="CMakeLists.txt" />
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "Core/Compatibility.h"
|
||||||
|
|
||||||
enum CPUCore {
|
enum CPUCore {
|
||||||
CPU_INTERPRETER,
|
CPU_INTERPRETER,
|
||||||
CPU_JIT,
|
CPU_JIT,
|
||||||
|
@ -69,4 +71,6 @@ struct CoreParameter {
|
||||||
bool frozen;
|
bool frozen;
|
||||||
|
|
||||||
FileLoader *mountIsoLoader;
|
FileLoader *mountIsoLoader;
|
||||||
|
|
||||||
|
Compatibility compat;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1237,7 +1237,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr)
|
||||||
return SCE_KERNEL_ERROR_ILLEGAL_SIZE;
|
return SCE_KERNEL_ERROR_ILLEGAL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG(SCEKERNEL, "sceKernelReferThreadStatus(%i, %08x)", threadID, statusPtr);
|
VERBOSE_LOG(SCEKERNEL, "sceKernelReferThreadStatus(%i, %08x)", threadID, statusPtr);
|
||||||
|
|
||||||
t->nt.nativeSize = THREADINFO_SIZE_AFTER_260;
|
t->nt.nativeSize = THREADINFO_SIZE_AFTER_260;
|
||||||
if (wantedSize != 0)
|
if (wantedSize != 0)
|
||||||
|
@ -1248,7 +1248,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_LOG(SCEKERNEL, "sceKernelReferThreadStatus(%i, %08x)", threadID, statusPtr);
|
VERBOSE_LOG(SCEKERNEL, "sceKernelReferThreadStatus(%i, %08x)", threadID, statusPtr);
|
||||||
|
|
||||||
t->nt.nativeSize = THREADINFO_SIZE;
|
t->nt.nativeSize = THREADINFO_SIZE;
|
||||||
u32 sz = std::min(THREADINFO_SIZE, wantedSize);
|
u32 sz = std::min(THREADINFO_SIZE, wantedSize);
|
||||||
|
|
|
@ -276,7 +276,6 @@ inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const
|
||||||
MemcpyUnchecked(GetPointer(to_address), from_address, len);
|
MemcpyUnchecked(GetPointer(to_address), from_address, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This considers 0x88900000 a valid address. Probably not good.
|
|
||||||
inline bool IsValidAddress(const u32 address) {
|
inline bool IsValidAddress(const u32 address) {
|
||||||
if ((address & 0x3E000000) == 0x08000000) {
|
if ((address & 0x3E000000) == 0x08000000) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -204,6 +204,11 @@ void CPU_Init() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Here we have read the PARAM.SFO, let's see if we need any compatibility overrides.
|
||||||
|
std::string discID = g_paramSFO.GetValueString("DISC_ID");
|
||||||
|
if (!discID.empty())
|
||||||
|
coreParameter.compat.Load(discID);
|
||||||
|
|
||||||
Memory::Init();
|
Memory::Init();
|
||||||
mipsr4k.Reset();
|
mipsr4k.Reset();
|
||||||
|
|
||||||
|
|
|
@ -466,6 +466,17 @@ void DIRECTX9_GPU::UpdateCmdInfo() {
|
||||||
cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
|
cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
|
||||||
cmdInfo_[GE_CMD_VERTEXTYPE].func = &DIRECTX9_GPU::Execute_VertexType;
|
cmdInfo_[GE_CMD_VERTEXTYPE].func = &DIRECTX9_GPU::Execute_VertexType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 features = 0;
|
||||||
|
|
||||||
|
// Set some flags that may be convenient in the future if we merge the backends more.
|
||||||
|
features |= GPU_SUPPORTS_BLEND_MINMAX;
|
||||||
|
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
|
||||||
|
|
||||||
|
if (!PSP_CoreParameter().compat.flags().NoDepthRounding)
|
||||||
|
features |= GPU_ROUND_DEPTH_TO_16BIT;
|
||||||
|
|
||||||
|
gstate_c.featureFlags = features;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIRECTX9_GPU::~DIRECTX9_GPU() {
|
DIRECTX9_GPU::~DIRECTX9_GPU() {
|
||||||
|
|
|
@ -226,7 +226,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gstate.isModeThrough()) {
|
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
|
WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||||
|
|
||||||
// Confirmed: Through mode gets through exactly the same in GL and D3D in Phantasy Star: Text is 38023.0 in the test scene.
|
// Confirmed: Through mode gets through exactly the same in GL and D3D in Phantasy Star: Text is 38023.0 in the test scene.
|
||||||
|
|
||||||
if (!gstate.isModeThrough()) {
|
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
||||||
// The Z range in D3D is different but we compensate for that using parameters.
|
// The Z range in D3D is different but we compensate for that using parameters.
|
||||||
WRITE(p, "\nfloat4 depthRoundZVP(float4 v) {\n");
|
WRITE(p, "\nfloat4 depthRoundZVP(float4 v) {\n");
|
||||||
|
@ -328,7 +328,11 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||||
if (gstate.isModeThrough()) {
|
if (gstate.isModeThrough()) {
|
||||||
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n");
|
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n");
|
||||||
} else {
|
} else {
|
||||||
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n");
|
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
|
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n");
|
||||||
|
} else {
|
||||||
|
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj);\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Step 1: World Transform / Skinning
|
// Step 1: World Transform / Skinning
|
||||||
|
@ -417,7 +421,11 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||||
WRITE(p, " float4 viewPos = float4(mul(float4(worldpos, 1.0), u_view), 1.0);\n");
|
WRITE(p, " float4 viewPos = float4(mul(float4(worldpos, 1.0), u_view), 1.0);\n");
|
||||||
|
|
||||||
// Final view and projection transforms.
|
// Final view and projection transforms.
|
||||||
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n");
|
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
|
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n");
|
||||||
|
} else {
|
||||||
|
WRITE(p, " Out.gl_Position = mul(viewPos, u_proj);\n");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Declare variables for dots for shade mapping if needed.
|
// TODO: Declare variables for dots for shade mapping if needed.
|
||||||
|
|
||||||
|
|
|
@ -558,9 +558,13 @@ void GLES_GPU::CheckGPUFeatures() {
|
||||||
if (!gl_extensions.IsGLES)
|
if (!gl_extensions.IsGLES)
|
||||||
features |= GPU_SUPPORTS_LOGIC_OP;
|
features |= GPU_SUPPORTS_LOGIC_OP;
|
||||||
|
|
||||||
if (gl_extensions.GLES3 || !gl_extensions.IsGLES) {
|
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
||||||
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
|
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
|
||||||
}
|
|
||||||
|
// In the future, also disable this when we get a proper 16-bit depth buffer.
|
||||||
|
if (!PSP_CoreParameter().compat.flags().NoDepthRounding)
|
||||||
|
features |= GPU_ROUND_DEPTH_TO_16BIT;
|
||||||
|
|
||||||
|
|
||||||
#ifdef MOBILE_DEVICE
|
#ifdef MOBILE_DEVICE
|
||||||
// Arguably, we should turn off GPU_IS_MOBILE on like modern Tegras, etc.
|
// Arguably, we should turn off GPU_IS_MOBILE on like modern Tegras, etc.
|
||||||
|
|
|
@ -354,7 +354,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||||
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
|
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gstate.isModeThrough()) {
|
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
WRITE(p, "uniform highp vec4 u_depthRange;\n");
|
WRITE(p, "uniform highp vec4 u_depthRange;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||||
}
|
}
|
||||||
|
|
||||||
// See comment above this function (GenerateVertexShader).
|
// See comment above this function (GenerateVertexShader).
|
||||||
if (!gstate.isModeThrough()) {
|
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
||||||
WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n");
|
WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n");
|
||||||
WRITE(p, " float z = v.z / v.w;\n");
|
WRITE(p, " float z = v.z / v.w;\n");
|
||||||
|
@ -418,7 +418,11 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||||
WRITE(p, " gl_Position = u_proj_through * vec4(position.xyz, 1.0);\n");
|
WRITE(p, " gl_Position = u_proj_through * vec4(position.xyz, 1.0);\n");
|
||||||
} else {
|
} else {
|
||||||
// The viewport is used in this case, so need to compensate for that.
|
// The viewport is used in this case, so need to compensate for that.
|
||||||
WRITE(p, " gl_Position = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n");
|
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
|
WRITE(p, " gl_Position = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n");
|
||||||
|
} else {
|
||||||
|
WRITE(p, " gl_Position = u_proj * vec4(position.xyz, 1.0);\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Step 1: World Transform / Skinning
|
// Step 1: World Transform / Skinning
|
||||||
|
@ -511,7 +515,11 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||||
WRITE(p, " vec4 viewPos = u_view * vec4(worldpos, 1.0);\n");
|
WRITE(p, " vec4 viewPos = u_view * vec4(worldpos, 1.0);\n");
|
||||||
|
|
||||||
// Final view and projection transforms.
|
// Final view and projection transforms.
|
||||||
WRITE(p, " gl_Position = depthRoundZVP(u_proj * viewPos);\n");
|
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||||
|
WRITE(p, " gl_Position = depthRoundZVP(u_proj * viewPos);\n");
|
||||||
|
} else {
|
||||||
|
WRITE(p, " gl_Position = u_proj * viewPos;\n");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Declare variables for dots for shade mapping if needed.
|
// TODO: Declare variables for dots for shade mapping if needed.
|
||||||
|
|
||||||
|
|
|
@ -454,6 +454,7 @@ enum {
|
||||||
GPU_SUPPORTS_BLEND_MINMAX = FLAG_BIT(4),
|
GPU_SUPPORTS_BLEND_MINMAX = FLAG_BIT(4),
|
||||||
GPU_SUPPORTS_LOGIC_OP = FLAG_BIT(5),
|
GPU_SUPPORTS_LOGIC_OP = FLAG_BIT(5),
|
||||||
GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20),
|
GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20),
|
||||||
|
GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer
|
||||||
GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24),
|
GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24),
|
||||||
GPU_SUPPORTS_FBO = FLAG_BIT(25),
|
GPU_SUPPORTS_FBO = FLAG_BIT(25),
|
||||||
GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT = FLAG_BIT(26),
|
GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT = FLAG_BIT(26),
|
||||||
|
|
|
@ -199,6 +199,7 @@ EXEC_AND_LIB_FILES := \
|
||||||
$(SRC)/Core/HW/SasAudio.cpp.arm \
|
$(SRC)/Core/HW/SasAudio.cpp.arm \
|
||||||
$(SRC)/Core/HW/StereoResampler.cpp.arm \
|
$(SRC)/Core/HW/StereoResampler.cpp.arm \
|
||||||
$(SRC)/Core/Core.cpp \
|
$(SRC)/Core/Core.cpp \
|
||||||
|
$(SRC)/Core/Compatibility.cpp \
|
||||||
$(SRC)/Core/Config.cpp \
|
$(SRC)/Core/Config.cpp \
|
||||||
$(SRC)/Core/CoreTiming.cpp \
|
$(SRC)/Core/CoreTiming.cpp \
|
||||||
$(SRC)/Core/CwCheat.cpp \
|
$(SRC)/Core/CwCheat.cpp \
|
||||||
|
|
5
assets/compat.ini
Normal file
5
assets/compat.ini
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Fight Night Round 3
|
||||||
|
[ULES00270]
|
||||||
|
NoDepthRounding = true
|
||||||
|
[ULUS10066]
|
||||||
|
NoDepthRounding = true
|
Loading…
Add table
Add a link
Reference in a new issue