mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
Ported from EmuCoreX with sashkinbro's approval. The GPU family alone was never enough to decide behaviour: the same Mali part behaves differently under ARM's proprietary driver than under Mesa PanVK, a lesson this tree learned twice the expensive way - the r44p1 DEVICE_LOST fix had to be gated on driverID rather than vendorID, and the 8 Elite push-descriptor disable likewise. Driver identity, version and a bug set are now recorded in a table, so the next device quirk is an entry rather than another bespoke branch. Twenty-five rules, with match confidence so a vendor-wide rule never overrides a driver-version-specific one. The shaders gain gpu_bitwise_and / gpu_bitwise_not / gpu_boolean_not, whose bodies the device emits: plain a & b normally, scalarized where the database says the driver miscompiles vector bitwise ops. A device matching no rule renders exactly as before. opengl/tfx_fs.glsl already carried this fix as IAND3/UAND2/UAND4 macros gated on GPU_PROFILE_MALI. Those are replaced by the shared helpers, but the GL macro is deliberately (workaround || IsMaliGPUProfile()): Mali reached through ANGLE or Panfrost resolves a non-ARM driver and matches no rule, so a database-only gate would have silently removed a fix those users have today. Widening only. SHADER_CACHE_VERSION 108 -> 109. Every TFX and convert shader's source text changed, so a blob cached from 108 no longer matches the source that produced it; without the bump users would get stale binaries and garbage rendering after updating. RewriteConstantLoads is deliberately absent - the database records BrokenConstantLoad with no workaround bits, so the macro would be permanently zero and the shader code dead. Shaders validated offline with glslc across 136 Vulkan and 296 GL/GLES permutations, every macro on and off; the failure set is byte-identical to the pre-change baseline.
265 lines
7.4 KiB
C++
265 lines
7.4 KiB
C++
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#pragma once
|
|
|
|
#include "common/Pcsx2Defs.h"
|
|
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
enum class GpuProfileOverride : u8
|
|
{
|
|
Auto,
|
|
Mali,
|
|
Adreno,
|
|
PowerVR,
|
|
Xclipse,
|
|
};
|
|
|
|
enum class RuntimeGpuProfile : u8
|
|
{
|
|
Unknown,
|
|
Mali,
|
|
Adreno,
|
|
PowerVR,
|
|
Xclipse,
|
|
/// Apple Silicon (M-series / A-series). A TBDR like the mobile parts, but it is NOT one of
|
|
/// them and must never inherit their workarounds — before this existed, desktop GL resolved
|
|
/// anything not-Mali to Adreno, so an M2 ran Adreno-only paths (reported by bmd: "GL: Adreno -
|
|
/// routing depth feedback through the depth sampler"). Distinct from Unknown so the tiler-ness
|
|
/// can be acted on deliberately later rather than by accident.
|
|
Apple,
|
|
};
|
|
|
|
enum class MobileGpuArchitecture : u8
|
|
{
|
|
Unknown,
|
|
Adreno2xx,
|
|
Adreno3xx,
|
|
Adreno4xx,
|
|
Adreno5xx,
|
|
Adreno6xx,
|
|
Adreno7xx,
|
|
Adreno8xx,
|
|
AdrenoX,
|
|
MaliUtgard,
|
|
MaliMidgard,
|
|
MaliBifrost,
|
|
MaliValhall1,
|
|
MaliValhall2,
|
|
MaliValhall3,
|
|
MaliFifthGen,
|
|
MaliG1,
|
|
PowerVR,
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------------------------
|
|
// Driver identity and known-bug model, ported from EmuCoreX (sashkinbro) with his approval.
|
|
//
|
|
// The GPU family alone is not enough to decide behaviour: the same Mali part behaves differently
|
|
// under Arm's proprietary driver than under Mesa PanVK, which is a lesson this tree learned the
|
|
// expensive way (the r44p1 DEVICE_LOST fix had to be gated on driverID, not vendorID, and the
|
|
// 8 Elite push-descriptor disable likewise). Recording it as driver + version + a bug set means
|
|
// the next device-specific quirk is a table entry rather than another bespoke branch.
|
|
// ---------------------------------------------------------------------------------------------
|
|
|
|
enum class MobileGpuApi : u8
|
|
{
|
|
Unknown,
|
|
OpenGL,
|
|
Vulkan,
|
|
};
|
|
|
|
// Deliberately independent of VkDriverId so profile resolution stays unit-testable without
|
|
// pulling in Vulkan headers, and so the OpenGL path can use the same table.
|
|
enum class MobileGpuDriver : u8
|
|
{
|
|
Unknown,
|
|
ArmProprietary,
|
|
MesaPanVK,
|
|
QualcommProprietary,
|
|
MesaTurnip,
|
|
ImaginationProprietary,
|
|
MesaPowerVR,
|
|
Angle,
|
|
};
|
|
|
|
/// How specifically a profile was matched. A rule matched on the exact driver version is worth
|
|
/// more than one matched on the vendor alone, so a broad entry never overrides a precise one.
|
|
enum class DriverProfileConfidence : u8
|
|
{
|
|
Unknown,
|
|
Vendor,
|
|
Model,
|
|
Driver,
|
|
DriverVersion,
|
|
};
|
|
|
|
/// Observed driver defects. Naming is descriptive of the DEFECT, not of the fix, so one bug can
|
|
/// drive several workarounds and the table stays readable.
|
|
enum class DriverBug : u8
|
|
{
|
|
BrokenBufferStreaming,
|
|
BrokenUnsynchronizedMapping,
|
|
BrokenNegatedBoolean,
|
|
BrokenVectorBitwiseAnd,
|
|
BrokenBitwiseOpNegation,
|
|
BrokenPrimitiveRestart,
|
|
BrokenPushDescriptors,
|
|
BrokenProvokingVertex,
|
|
BrokenAttachmentFeedbackLoopLayout,
|
|
BrokenSubpassFeedback,
|
|
BrokenColorWriteMaskWithDepthTest,
|
|
BrokenDepthStencilDiscard,
|
|
BrokenReversedDepthRange,
|
|
SlowCachedReadbackMemory,
|
|
SlowOptimalImageToBufferCopy,
|
|
BrokenClearLoadOpRenderPass,
|
|
Broken16BitTextureFormats,
|
|
BrokenGenerateMipmapTallTexture,
|
|
BrokenEmptyRenderPass,
|
|
BrokenConstantLoad,
|
|
BrokenUniformIndexing,
|
|
BrokenVSync,
|
|
BrokenMultithreadedShaderCompilation,
|
|
BrokenDynamicRendering,
|
|
BrokenImagelessFramebuffer,
|
|
BrokenExtendedDynamicState,
|
|
BrokenPrimitiveTopologyDynamicState,
|
|
BrokenGraphicsPipelineLibrary,
|
|
Count,
|
|
};
|
|
|
|
/// What we actually DO about a bug. Kept separate from [DriverBug] because the same mitigation
|
|
/// answers several defects, and because a workaround can be forced on for testing without
|
|
/// claiming the device has the bug.
|
|
enum class DriverWorkaround : u8
|
|
{
|
|
RewriteBooleanNegation,
|
|
ScalarizeVectorBitwiseAnd,
|
|
StoreBitwiseNegationInTemporary,
|
|
UseDescriptorSets,
|
|
DisableProvokingVertex,
|
|
DisableAttachmentFeedbackLoopLayout,
|
|
EmulateColorWriteMask,
|
|
PreferCoherentReadback,
|
|
UseStagingImageForReadback,
|
|
AvoidClearLoadOpRenderPass,
|
|
GenerateMipmapManuallyForTallTextures,
|
|
RewriteUniformIndexing,
|
|
ForceFifoPresent,
|
|
AlignSwapchainWidthTo32,
|
|
Count,
|
|
};
|
|
|
|
struct MobileDriverVersion
|
|
{
|
|
u32 raw = 0;
|
|
u16 major = 0;
|
|
u16 minor = 0;
|
|
u16 patch = 0;
|
|
u32 build = 0;
|
|
bool known = false;
|
|
bool legacy_hash = false;
|
|
};
|
|
|
|
/// Everything the resolver is allowed to look at. Filled from VkPhysicalDeviceProperties on the
|
|
/// Vulkan path and from the GL strings otherwise.
|
|
struct MobileDriverContext
|
|
{
|
|
MobileGpuApi api = MobileGpuApi::Unknown;
|
|
u32 vendor_id = 0;
|
|
u32 device_id = 0;
|
|
u32 driver_version = 0;
|
|
u32 driver_id = 0;
|
|
u32 api_version = 0;
|
|
u32 android_sdk = 0;
|
|
u32 max_draw_indirect_count = 0;
|
|
std::string_view driver_name;
|
|
std::string_view driver_info;
|
|
std::string_view api_version_string;
|
|
};
|
|
|
|
struct MobileDriverProfile
|
|
{
|
|
static constexpr u32 DATABASE_VERSION = 1;
|
|
|
|
MobileGpuApi api = MobileGpuApi::Unknown;
|
|
MobileGpuDriver driver = MobileGpuDriver::Unknown;
|
|
MobileDriverVersion version;
|
|
u64 bugs = 0;
|
|
u64 workarounds = 0;
|
|
u32 matched_rule_count = 0;
|
|
DriverProfileConfidence confidence = DriverProfileConfidence::Unknown;
|
|
/// True when nothing in the table matched and the safe defaults are in force.
|
|
bool conservative_fallback = true;
|
|
std::string driver_name;
|
|
|
|
constexpr bool HasBug(DriverBug bug) const
|
|
{
|
|
return (bugs & (u64{1} << static_cast<u8>(bug))) != 0;
|
|
}
|
|
|
|
constexpr bool UsesWorkaround(DriverWorkaround workaround) const
|
|
{
|
|
return (workarounds & (u64{1} << static_cast<u8>(workaround))) != 0;
|
|
}
|
|
};
|
|
|
|
// Both sets are u64 bitfields, so neither enum may exceed 64 entries without widening them.
|
|
static_assert(static_cast<u8>(DriverBug::Count) <= 64);
|
|
static_assert(static_cast<u8>(DriverWorkaround::Count) <= 64);
|
|
|
|
struct MobileGsTuning
|
|
{
|
|
bool constrained = true;
|
|
bool prefer_new_textures = false;
|
|
bool force_partial_texture_preloading = true;
|
|
u32 pooled_targets = 96;
|
|
u32 target_age = 8;
|
|
u32 pooled_textures = 96;
|
|
u32 texture_age = 6;
|
|
};
|
|
|
|
struct MobileGpuIdentity
|
|
{
|
|
MobileGpuArchitecture architecture = MobileGpuArchitecture::Unknown;
|
|
u16 model_number = 0;
|
|
u8 core_count = 0;
|
|
bool recognized = false;
|
|
std::string name = "Unknown";
|
|
};
|
|
|
|
struct GpuProfileSelection
|
|
{
|
|
GpuProfileOverride override_mode = GpuProfileOverride::Auto;
|
|
RuntimeGpuProfile runtime_profile = RuntimeGpuProfile::Unknown;
|
|
bool is_mediatek_soc = false;
|
|
MobileGpuIdentity gpu;
|
|
MobileGsTuning gs_tuning;
|
|
MobileDriverProfile driver;
|
|
std::string hints;
|
|
};
|
|
|
|
class GpuProfileDetector
|
|
{
|
|
public:
|
|
static GpuProfileOverride ParseOverride(std::string_view value);
|
|
static const char* OverrideToConfigString(GpuProfileOverride value);
|
|
static const char* OverrideToString(GpuProfileOverride value);
|
|
static const char* RuntimeProfileToString(RuntimeGpuProfile value);
|
|
static const char* ArchitectureToString(MobileGpuArchitecture value);
|
|
static const char* ApiToString(MobileGpuApi value);
|
|
static const char* DriverToString(MobileGpuDriver value);
|
|
static const char* BugToString(DriverBug value);
|
|
static const char* WorkaroundToString(DriverWorkaround value);
|
|
|
|
static GpuProfileSelection Resolve(std::string_view override_value, std::string_view gpu_vendor,
|
|
std::string_view gpu_renderer_or_name);
|
|
/// Overload that also resolves the driver profile. The three-argument form keeps working and
|
|
/// simply leaves GpuProfileSelection::driver in its conservative-fallback state.
|
|
static GpuProfileSelection Resolve(std::string_view override_value, std::string_view gpu_vendor,
|
|
std::string_view gpu_renderer_or_name, const MobileDriverContext& driver_context);
|
|
};
|