diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp index 6e97b010e7..d7fe873b1d 100644 --- a/Source/Core/VideoCommon/DriverDetails.cpp +++ b/Source/Core/VideoCommon/DriverDetails.cpp @@ -126,6 +126,8 @@ constexpr BugInfo m_known_bugs[] = { -1.0, -1.0, true}, {API_VULKAN, OS_ALL, VENDOR_ARM, DRIVER_ARM, Family::UNKNOWN, BUG_BROKEN_VECTOR_BITWISE_AND, -1.0, -1.0, true}, + {API_OPENGL, OS_WINDOWS, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_BROKEN_SSBO_FIELD_ATOMICS, + -1.0, -1.0, true}, }; static std::map m_bugs; diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 27dd77a1ad..b62a0f4450 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -298,6 +298,14 @@ enum Bug // Started version: -1 // Ended version: -1 BUG_BROKEN_VECTOR_BITWISE_AND, + + // BUG: Atomic writes to different fields or array elements of an SSBO have no effect, only + // writing to the first field/element works. This causes bounding box emulation to give garbage + // values under OpenGL. + // Affected devices: AMD (Windows) + // Started version: -1 + // Ended version: -1 + BUG_BROKEN_SSBO_FIELD_ATOMICS, }; // Initializes our internal vendor, device family, and driver version diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 16fb7766e9..551fd3dc2d 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -451,20 +451,37 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type, if (bounding_box) { + if (api_type == APIType::D3D) + { + out.Write("globallycoherent RWBuffer bbox_data : register(u2);\n" + "#define atomicMin InterlockedMin\n" + "#define atomicMax InterlockedMax"); + } + else + { + out.Write("SSBO_BINDING(0) buffer BBox {{\n"); + + if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_SSBO_FIELD_ATOMICS)) + { + // AMD drivers on Windows seemingly ignore atomic writes to fields or array elements of an + // SSBO other than the first one, but using an int4 seems to work fine + out.Write(" int4 bbox_data;\n"); + } + else + { + // The Metal shader compiler fails to compile the atomic instructions when operating on + // individual components of a vector + out.Write(" int bbox_data[4];\n"); + } + + out.Write("}};"); + } + out.Write(R"( -#ifdef API_D3D -globallycoherent RWBuffer bbox_data : register(u2); -#define atomicMin InterlockedMin -#define atomicMax InterlockedMax #define bbox_left bbox_data[0] #define bbox_right bbox_data[1] #define bbox_top bbox_data[2] #define bbox_bottom bbox_data[3] -#else -SSBO_BINDING(0) buffer BBox {{ - int bbox_left, bbox_right, bbox_top, bbox_bottom; -}}; -#endif void UpdateBoundingBoxBuffer(int2 min_pos, int2 max_pos) {{ if (bbox_left > min_pos.x)