mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-12-21 07:22:21 +00:00
Implement workaround for Mesa triangle strip bug. (#428)
* Convert restart indices to degenerate triangles for Mesa. * Check for Mesa to enable the triangle strip workaround. * Remove _WIN32 ifndefs.
This commit is contained in:
parent
4aeee49561
commit
14faa17cd8
1 changed files with 192 additions and 0 deletions
|
|
@ -285,6 +285,8 @@ static bool g_vulkan = false;
|
||||||
static constexpr bool g_vulkan = true;
|
static constexpr bool g_vulkan = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static bool g_mesaTriangleStripWorkaround = false;
|
||||||
|
|
||||||
static constexpr bool g_hardwareResolve = true;
|
static constexpr bool g_hardwareResolve = true;
|
||||||
static constexpr bool g_hardwareDepthResolve = true;
|
static constexpr bool g_hardwareDepthResolve = true;
|
||||||
|
|
||||||
|
|
@ -1699,6 +1701,14 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
||||||
|
|
||||||
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
|
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (interfaceFunction == CreateVulkanInterfaceWrapper)
|
||||||
|
{
|
||||||
|
// Enable triangle strip workaround if we are on the Mesa RADV driver, as it currently has a bug where
|
||||||
|
// restart indices cause triangles to be culled incorrectly. Converting them to degenerate triangles fixes it.
|
||||||
|
g_mesaTriangleStripWorkaround = deviceDescription.name.find(" (RADV ") != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2318,6 +2328,7 @@ static void DrawProfiler()
|
||||||
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
|
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
|
||||||
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
|
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
|
||||||
ImGui::Text("Dynamic Depth Bias: %s", g_capabilities.dynamicDepthBias ? "Supported" : "Unsupported");
|
ImGui::Text("Dynamic Depth Bias: %s", g_capabilities.dynamicDepthBias ? "Supported" : "Unsupported");
|
||||||
|
ImGui::Text("Triangle Strip Workaround: %s", g_mesaTriangleStripWorkaround ? "Enabled" : "Disabled");
|
||||||
ImGui::NewLine();
|
ImGui::NewLine();
|
||||||
|
|
||||||
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
|
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
|
||||||
|
|
@ -7402,6 +7413,187 @@ bool FxShadowMapMidAsmHook(PPCRegister& r4, PPCRegister& r5, PPCRegister& r6, PP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There is a driver bug on Mesa where restart indices cause incorrect culling and prevent some triangles from being rendered.
|
||||||
|
// Restart indices can be converted to degenerate triangles as a workaround until this issue gets fixed.
|
||||||
|
static void ConvertToDegenerateTriangles(uint16_t* indices, uint32_t indexCount, uint16_t*& newIndices, uint32_t& newIndexCount)
|
||||||
|
{
|
||||||
|
newIndices = reinterpret_cast<uint16_t*>(g_userHeap.Alloc(indexCount * sizeof(uint16_t) * 3));
|
||||||
|
newIndexCount = 0;
|
||||||
|
|
||||||
|
bool stripStart = true;
|
||||||
|
uint32_t stripSize = 0;
|
||||||
|
uint16_t lastIndex = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < indexCount; i++)
|
||||||
|
{
|
||||||
|
uint16_t index = indices[i];
|
||||||
|
if (index == 0xFFFF)
|
||||||
|
{
|
||||||
|
if ((stripSize % 2) != 0)
|
||||||
|
newIndices[newIndexCount++] = lastIndex;
|
||||||
|
|
||||||
|
stripStart = true;
|
||||||
|
stripSize = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (stripStart && newIndexCount != 0)
|
||||||
|
{
|
||||||
|
newIndices[newIndexCount++] = lastIndex;
|
||||||
|
newIndices[newIndexCount++] = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
newIndices[newIndexCount++] = index;
|
||||||
|
stripStart = false;
|
||||||
|
++stripSize;
|
||||||
|
lastIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MeshResource
|
||||||
|
{
|
||||||
|
SWA_INSERT_PADDING(0x4);
|
||||||
|
be<uint32_t> indexCount;
|
||||||
|
be<uint32_t> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<uint16_t*> g_newIndicesToFree;
|
||||||
|
|
||||||
|
// Hedgehog::Mirage::CMeshData::Make
|
||||||
|
PPC_FUNC_IMPL(__imp__sub_82E44AF8);
|
||||||
|
PPC_FUNC(sub_82E44AF8)
|
||||||
|
{
|
||||||
|
uint16_t* newIndicesToFree = nullptr;
|
||||||
|
|
||||||
|
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
||||||
|
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
||||||
|
{
|
||||||
|
auto meshResource = reinterpret_cast<MeshResource*>(base + ctx.r4.u32);
|
||||||
|
|
||||||
|
if (meshResource->indexCount != 0)
|
||||||
|
{
|
||||||
|
uint16_t* newIndices;
|
||||||
|
uint32_t newIndexCount;
|
||||||
|
|
||||||
|
ConvertToDegenerateTriangles(
|
||||||
|
reinterpret_cast<uint16_t*>(base + meshResource->indices),
|
||||||
|
meshResource->indexCount,
|
||||||
|
newIndices,
|
||||||
|
newIndexCount);
|
||||||
|
|
||||||
|
meshResource->indexCount = newIndexCount;
|
||||||
|
meshResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
||||||
|
|
||||||
|
if (PPC_LOAD_U32(0x83396E98) != NULL)
|
||||||
|
{
|
||||||
|
// If index buffers are getting merged, new indices need to survive until the merge happens.
|
||||||
|
g_newIndicesToFree.push_back(newIndices);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise, we can free it immediately.
|
||||||
|
newIndicesToFree = newIndices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__imp__sub_82E44AF8(ctx, base);
|
||||||
|
|
||||||
|
if (newIndicesToFree != nullptr)
|
||||||
|
g_userHeap.Free(newIndicesToFree);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hedgehog::Mirage::CShareVertexBuffer::Reset
|
||||||
|
PPC_FUNC_IMPL(__imp__sub_82E250D0);
|
||||||
|
PPC_FUNC(sub_82E250D0)
|
||||||
|
{
|
||||||
|
__imp__sub_82E250D0(ctx, base);
|
||||||
|
|
||||||
|
for (auto newIndicesToFree : g_newIndicesToFree)
|
||||||
|
g_userHeap.Free(newIndicesToFree);
|
||||||
|
|
||||||
|
g_newIndicesToFree.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LightAndIndexBufferResourceV1
|
||||||
|
{
|
||||||
|
SWA_INSERT_PADDING(0x4);
|
||||||
|
be<uint32_t> indexCount;
|
||||||
|
be<uint32_t> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hedgehog::Mirage::CLightAndIndexBufferData::MakeV1
|
||||||
|
PPC_FUNC_IMPL(__imp__sub_82E3AFC8);
|
||||||
|
PPC_FUNC(sub_82E3AFC8)
|
||||||
|
{
|
||||||
|
uint16_t* newIndices = nullptr;
|
||||||
|
|
||||||
|
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
||||||
|
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
||||||
|
{
|
||||||
|
auto lightAndIndexBufferResource = reinterpret_cast<LightAndIndexBufferResourceV1*>(base + ctx.r4.u32);
|
||||||
|
|
||||||
|
if (lightAndIndexBufferResource->indexCount != 0)
|
||||||
|
{
|
||||||
|
uint32_t newIndexCount;
|
||||||
|
|
||||||
|
ConvertToDegenerateTriangles(
|
||||||
|
reinterpret_cast<uint16_t*>(base + lightAndIndexBufferResource->indices),
|
||||||
|
lightAndIndexBufferResource->indexCount,
|
||||||
|
newIndices,
|
||||||
|
newIndexCount);
|
||||||
|
|
||||||
|
lightAndIndexBufferResource->indexCount = newIndexCount;
|
||||||
|
lightAndIndexBufferResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__imp__sub_82E3AFC8(ctx, base);
|
||||||
|
|
||||||
|
if (newIndices != nullptr)
|
||||||
|
g_userHeap.Free(newIndices);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LightAndIndexBufferResourceV5
|
||||||
|
{
|
||||||
|
SWA_INSERT_PADDING(0x8);
|
||||||
|
be<uint32_t> indexCount;
|
||||||
|
be<uint32_t> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hedgehog::Mirage::CLightAndIndexBufferData::MakeV5
|
||||||
|
PPC_FUNC_IMPL(__imp__sub_82E3B1C0);
|
||||||
|
PPC_FUNC(sub_82E3B1C0)
|
||||||
|
{
|
||||||
|
uint16_t* newIndices = nullptr;
|
||||||
|
|
||||||
|
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
||||||
|
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
||||||
|
{
|
||||||
|
auto lightAndIndexBufferResource = reinterpret_cast<LightAndIndexBufferResourceV5*>(base + ctx.r4.u32);
|
||||||
|
|
||||||
|
if (lightAndIndexBufferResource->indexCount != 0)
|
||||||
|
{
|
||||||
|
uint32_t newIndexCount;
|
||||||
|
|
||||||
|
ConvertToDegenerateTriangles(
|
||||||
|
reinterpret_cast<uint16_t*>(base + lightAndIndexBufferResource->indices),
|
||||||
|
lightAndIndexBufferResource->indexCount,
|
||||||
|
newIndices,
|
||||||
|
newIndexCount);
|
||||||
|
|
||||||
|
lightAndIndexBufferResource->indexCount = newIndexCount;
|
||||||
|
lightAndIndexBufferResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__imp__sub_82E3B1C0(ctx, base);
|
||||||
|
|
||||||
|
if (newIndices != nullptr)
|
||||||
|
g_userHeap.Free(newIndices);
|
||||||
|
}
|
||||||
|
|
||||||
GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice);
|
GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice);
|
||||||
|
|
||||||
GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource);
|
GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue