package net.minecraft.client.renderer; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.ImmutableMap.Builder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import com.mojang.blaze3d.systems.DeviceInfo; import com.mojang.blaze3d.systems.GpuDevice; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.logging.LogUtils; import java.io.IOException; import java.io.Reader; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.SimplePreparableReloadListener; import net.minecraft.util.StrictJsonParser; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.Zone; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class GpuWarnlistManager extends SimplePreparableReloadListener { private static final Logger LOGGER = LogUtils.getLogger(); private static final Identifier GPU_WARNLIST_LOCATION = Identifier.withDefaultNamespace("gpu_warnlist.json"); private ImmutableMap warnings = ImmutableMap.of(); private boolean showWarning; private boolean warningDismissed; public boolean hasWarnings() { return !this.warnings.isEmpty(); } public boolean willShowWarning() { return this.hasWarnings() && !this.warningDismissed; } public void showWarning() { this.showWarning = true; } public void dismissWarning() { this.warningDismissed = true; } public boolean isShowingWarning() { return this.showWarning && !this.warningDismissed; } public void resetWarnings() { this.showWarning = false; this.warningDismissed = false; } @Nullable public String getRendererWarnings() { return this.warnings.get("renderer"); } @Nullable public String getVersionWarnings() { return this.warnings.get("version"); } @Nullable public String getVendorWarnings() { return this.warnings.get("vendor"); } @Nullable public String getAllWarnings() { StringBuilder sb = new StringBuilder(); this.warnings.forEach((k, v) -> sb.append(k).append(": ").append(v)); return sb.isEmpty() ? null : sb.toString(); } protected GpuWarnlistManager.Preparations prepare(final ResourceManager manager, final ProfilerFiller profiler) { List rendererPatterns = Lists.newArrayList(); List versionPatterns = Lists.newArrayList(); List vendorPatterns = Lists.newArrayList(); JsonObject root = parseJson(manager, profiler); if (root != null) { Zone ignored = profiler.zone("compile_regex"); try { compilePatterns(root.getAsJsonArray("renderer"), rendererPatterns); compilePatterns(root.getAsJsonArray("version"), versionPatterns); compilePatterns(root.getAsJsonArray("vendor"), vendorPatterns); } catch (Throwable var11) { if (ignored != null) { try { ignored.close(); } catch (Throwable var10) { var11.addSuppressed(var10); } } throw var11; } if (ignored != null) { ignored.close(); } } return new GpuWarnlistManager.Preparations(rendererPatterns, versionPatterns, vendorPatterns); } protected void apply(final GpuWarnlistManager.Preparations preparations, final ResourceManager manager, final ProfilerFiller profiler) { this.warnings = preparations.apply(); } private static void compilePatterns(final JsonArray jsonArray, final List patternList) { jsonArray.forEach(e -> patternList.add(Pattern.compile(e.getAsString(), 2))); } @Nullable private static JsonObject parseJson(final ResourceManager manager, final ProfilerFiller profiler) { try { Zone ignored = profiler.zone("parse_json"); JsonObject var4; try { Reader resource = manager.openAsReader(GPU_WARNLIST_LOCATION); try { var4 = StrictJsonParser.parse(resource).getAsJsonObject(); } catch (Throwable var8) { if (resource != null) { try { resource.close(); } catch (Throwable var7) { var8.addSuppressed(var7); } } throw var8; } if (resource != null) { resource.close(); } } catch (Throwable var9) { if (ignored != null) { try { ignored.close(); } catch (Throwable var6) { var9.addSuppressed(var6); } } throw var9; } if (ignored != null) { ignored.close(); } return var4; } catch (JsonSyntaxException | IOException var10) { LOGGER.warn("Failed to load GPU warnlist", (Throwable)var10); return null; } } protected static final class Preparations { private final List rendererPatterns; private final List versionPatterns; private final List vendorPatterns; private Preparations(final List rendererPatterns, final List versionPatterns, final List vendorPatterns) { this.rendererPatterns = rendererPatterns; this.versionPatterns = versionPatterns; this.vendorPatterns = vendorPatterns; } private static String matchAny(final List patterns, final String input) { List allMatches = Lists.newArrayList(); for (Pattern pattern : patterns) { Matcher matcher = pattern.matcher(input); while (matcher.find()) { allMatches.add(matcher.group()); } } return String.join(", ", allMatches); } private ImmutableMap apply() { Builder map = new Builder<>(); GpuDevice device = RenderSystem.getDevice(); DeviceInfo deviceInfo = device.getDeviceInfo(); if (deviceInfo.backendName().equals("OpenGL")) { String rendererFails = matchAny(this.rendererPatterns, deviceInfo.name()); if (!rendererFails.isEmpty()) { map.put("renderer", rendererFails); } String versionFails = matchAny(this.versionPatterns, deviceInfo.driverInfo()); if (!versionFails.isEmpty()) { map.put("version", versionFails); } String vendorFails = matchAny(this.vendorPatterns, deviceInfo.vendorName()); if (!vendorFails.isEmpty()) { map.put("vendor", vendorFails); } } return map.build(); } } }