From 3a7fc265399b4a10a6ae499b0d015736e5464cba Mon Sep 17 00:00:00 2001 From: isXander Date: Thu, 28 Sep 2023 15:42:01 +0100 Subject: Fix ImageRendererManager not supplying completed image, fix compatibilty with VulkanMod (xCollateral/VulkanMod#303) --- .../yacl3/gui/image/ImageRendererManager.java | 89 ++++++++++++---------- .../dev/isxander/yacl3/mixin/MinecraftMixin.java | 5 -- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java b/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java index b1f133a..680a6da 100644 --- a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java +++ b/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java @@ -2,75 +2,86 @@ package dev.isxander.yacl3.gui.image; import com.mojang.blaze3d.systems.RenderSystem; import dev.isxander.yacl3.impl.utils.YACLConstants; +import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import java.util.Map; -import java.util.Queue; +import java.util.Optional; import java.util.concurrent.*; +import java.util.function.Supplier; public class ImageRendererManager { private static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor(task -> new Thread(task, "YACL Image Prep")); private static final Map> IMAGE_CACHE = new ConcurrentHashMap<>(); - private static final Queue> CREATION_QUEUE = new ConcurrentLinkedQueue<>(); + @SuppressWarnings("unchecked") public static CompletableFuture registerImage(ResourceLocation id, ImageRendererFactory factory) { - SINGLE_THREAD_EXECUTOR.submit(() -> { - try { - ImageRendererFactory.ImageSupplier supplier = factory.prepareImage(); - CREATION_QUEUE.add(new FactoryIDPair<>(id, supplier)); - } catch (Exception e) { - YACLConstants.LOGGER.error("Failed to prepare image '{}'", id, e); - IMAGE_CACHE.remove(id); - } - }); + if (IMAGE_CACHE.containsKey(id)) { + return (CompletableFuture) IMAGE_CACHE.get(id); + } var future = new CompletableFuture(); IMAGE_CACHE.put(id, future); + + SINGLE_THREAD_EXECUTOR.submit(() -> { + Supplier>> supplier = + factory.requiresOffThreadPreparation() + ? new CompletedSupplier<>(safelyPrepareFactory(id, factory)) + : () -> safelyPrepareFactory(id, factory); + + Minecraft.getInstance().execute(() -> completeImageFactory(id, supplier, future)); + }); + return (CompletableFuture) future; } - public static void pollImageFactories() { + private static void completeImageFactory(ResourceLocation id, Supplier>> supplier, CompletableFuture future) { RenderSystem.assertOnRenderThread(); - while (!CREATION_QUEUE.isEmpty()) { - FactoryIDPair pair = CREATION_QUEUE.poll(); - - // sanity check - this should never happen - if (!IMAGE_CACHE.containsKey(pair.id())) { - YACLConstants.LOGGER.error("Tried to finalise image '{}' but it was not found in cache.", pair.id()); - continue; - } - - ImageRenderer image; - try { - image = pair.supplier().completeImage(); - } catch (Exception e) { - YACLConstants.LOGGER.error("Failed to create image '{}'", pair.id(), e); - continue; - } + ImageRendererFactory.ImageSupplier completableImage = supplier.get().orElse(null); + if (completableImage == null) { + return; + } - CompletableFuture future = IMAGE_CACHE.get(pair.id()); - // another sanity check - this should never happen - if (future.isDone()) { - YACLConstants.LOGGER.error("Image '{}' was already completed", pair.id()); - continue; - } + // sanity check - this should never happen + if (future.isDone()) { + YACLConstants.LOGGER.error("Image '{}' was already completed", id); + return; + } - future.complete(image); + ImageRenderer image; + try { + image = completableImage.completeImage(); + } catch (Exception e) { + YACLConstants.LOGGER.error("Failed to create image '{}'", id, e); + return; } + + future.complete(image); } public static void closeAll() { SINGLE_THREAD_EXECUTOR.shutdownNow(); - CREATION_QUEUE.clear(); - IMAGE_CACHE.values().forEach(future -> { + IMAGE_CACHE.values().removeIf(future -> { if (future.isDone()) { future.join().close(); } + return true; }); - IMAGE_CACHE.clear(); } - private record FactoryIDPair(ResourceLocation id, ImageRendererFactory.ImageSupplier supplier) {} + private static Optional> safelyPrepareFactory(ResourceLocation id, ImageRendererFactory factory) { + try { + return Optional.of(factory.prepareImage()); + } catch (Exception e) { + YACLConstants.LOGGER.error("Failed to prepare image '{}'", id, e); + IMAGE_CACHE.remove(id); + return Optional.empty(); + } + } + + private record CompletedSupplier(T get) implements Supplier { + } + } diff --git a/common/src/main/java/dev/isxander/yacl3/mixin/MinecraftMixin.java b/common/src/main/java/dev/isxander/yacl3/mixin/MinecraftMixin.java index 0b228a1..45bc314 100644 --- a/common/src/main/java/dev/isxander/yacl3/mixin/MinecraftMixin.java +++ b/common/src/main/java/dev/isxander/yacl3/mixin/MinecraftMixin.java @@ -13,9 +13,4 @@ public class MinecraftMixin { private void closeImages(CallbackInfo ci) { ImageRendererManager.closeAll(); } - - @Inject(method = "runTick", at = @At(value = "HEAD")) - private void finaliseImages(boolean tick, CallbackInfo ci) { - ImageRendererManager.pollImageFactories(); - } } -- cgit