Skip to content

Commit

Permalink
Download and bind image texture on background executor
Browse files Browse the repository at this point in the history
  • Loading branch information
ustc-zzzz committed Oct 21, 2024
1 parent 2ca2125 commit 11ea4a6
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/main/java/org/teacon/slides/cache/ImageCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.net.HttpHeaders;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.Util;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.client.ClientProtocolException;
Expand Down Expand Up @@ -111,7 +112,7 @@ public CompletableFuture<Map.Entry<String, byte[]>> getResource(@Nonnull URI loc
LOGGER.warn(MARKER, "Failed to establish connection.", connError);
throw new CompletionException(connError);
}
});
}, Util.backgroundExecutor());
}

private CloseableHttpResponse createResponse(URI location, HttpCacheContext context, boolean online) throws IOException {
Expand Down
51 changes: 46 additions & 5 deletions src/main/java/org/teacon/slides/renderer/SlideState.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.teacon.slides.renderer;

import com.google.common.collect.ImmutableSet;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
Expand All @@ -21,6 +22,7 @@
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent;
import net.neoforged.neoforge.network.PacketDistributor;
import org.lwjgl.system.MemoryUtil;
import org.teacon.slides.ModRegistries;
import org.teacon.slides.SlideShow;
import org.teacon.slides.block.ProjectorBlockEntity;
Expand All @@ -32,14 +34,18 @@

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;

import static org.lwjgl.opengl.GL11C.*;

/**
* @author BloCamLimb
*/
Expand Down Expand Up @@ -131,7 +137,7 @@ private static ImmutableSet<BlockPos> tickBlockPosRequests() {
}

private static IntArrayList tickContainerChanges(AbstractContainerMenu playerContainer) {
var openingSlotIds = new LinkedHashMap<UUID, IntList>();
var openingSlotIds = new LinkedHashMap<UUID, IntList>();
var carriedEntry = playerContainer.getCarried().get(ModRegistries.SLIDE_ENTRY);
if (carriedEntry != null) {
openingSlotIds.computeIfAbsent(carriedEntry.id(), k -> new IntArrayList(1)).add(-1);
Expand Down Expand Up @@ -233,7 +239,7 @@ private void refresh(ProjectorURL location) {
var requestCounter = mRequestCounter;
ImageCache.getInstance()
.getResource(location.toUrl(), true)
.thenApplyAsync(SlideState::createTexture, RENDER_EXECUTOR)
.thenCompose(SlideState::createTexture)
.whenCompleteAsync((textureProvider, throwable) -> {
if (requestCounter == mRequestCounter) {
if (mState == State.INITIAL) {
Expand All @@ -252,7 +258,7 @@ private void refresh(ProjectorURL location) {
}, RENDER_EXECUTOR);
ImageCache.getInstance()
.getResource(location.toUrl(), false)
.thenApplyAsync(SlideState::createTexture, RENDER_EXECUTOR)
.thenCompose(SlideState::createTexture)
.whenCompleteAsync((textureProvider, throwable) -> {
if (requestCounter == mRequestCounter) {
if (textureProvider != null) {
Expand Down Expand Up @@ -307,12 +313,47 @@ public String toString() {
* @param nameDataEntry image file name & compressed image data
* @return texture
*/
private static TextureProvider createTexture(Map.Entry<String, byte[]> nameDataEntry) {
private static CompletableFuture<TextureProvider> createTexture(Map.Entry<String, byte[]> nameDataEntry) {
var name = nameDataEntry.getKey();
var data = nameDataEntry.getValue();
var future = new CompletableFuture<TextureProvider>();
var isGif = name.endsWith(".gif") || GIFDecoder.checkMagic(data);
var isWebP = name.endsWith(".webp") || WebPDecoder.checkMagic(data);
return isGif ? new AnimatedTextureProvider(name, data) : new StaticTextureProvider(name, data, isWebP);
if (isGif) {
RenderSystem.recordRenderCall(() -> {
try {
// TODO: decode GIFs asynchronously
future.complete(new AnimatedTextureProvider(name, data));
} catch (IOException e) {
future.completeExceptionally(e);
}
});
} else {
// color swizzle for web usage
var rgba = new int[]{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
// copy to native memory if it is not webp
var buffer = isWebP ? MemoryUtil.memAlloc(0) : MemoryUtil.memAlloc(data.length).put(data).rewind();
try {
// convert to RGBA
// noinspection resource
var image = isWebP ? WebPDecoder.toNativeImage(data, rgba) : NativeImage.read(buffer);
RenderSystem.recordRenderCall(() -> {
// noinspection TryFinallyCanBeTryWithResources
try {
future.complete(new StaticTextureProvider(name, image, rgba));
} catch (Throwable e) {
future.completeExceptionally(e);
} finally {
image.close();
}
});
} catch (IOException e) {
future.completeExceptionally(e);
} finally {
MemoryUtil.memFree(buffer);
}
}
return future;
}

public enum State {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.CompletionException;

import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.opengl.GL12C.GL_CLAMP_TO_EDGE;
Expand All @@ -37,7 +36,7 @@ public final class AnimatedTextureProvider implements TextureProvider {

private final int mCPUMemorySize;

public AnimatedTextureProvider(String name, byte[] data) {
public AnimatedTextureProvider(String name, byte[] data) throws IOException {
try {
mDecoder = new GIFDecoder(ByteBuffer.wrap(data), gRenderThreadDecoder);
final int width = mDecoder.getScreenWidth();
Expand Down Expand Up @@ -71,9 +70,9 @@ public AnimatedTextureProvider(String name, byte[] data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mFrame.rewind());
mRenderType = new SlideRenderType(mTexture);
mRecommendedName = name;
} catch (Throwable t) {
close();
throw new CompletionException(t);
} catch (IOException e) {
this.close();
throw e;
}
}

Expand Down
23 changes: 7 additions & 16 deletions src/main/java/org/teacon/slides/texture/StaticTextureProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import com.mojang.blaze3d.platform.NativeImage;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import org.lwjgl.system.MemoryUtil;
import org.teacon.slides.renderer.SlideRenderType;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.concurrent.CompletionException;

import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.opengl.GL12C.*;
Expand All @@ -30,13 +28,8 @@ public final class StaticTextureProvider implements TextureProvider {
private final String mRecommendedName;
private final int mWidth, mHeight;

public StaticTextureProvider(String name, byte[] data, boolean isWebP) {
// color swizzle for web usage
int[] rgbaSwizzle = new int[]{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
// copy to native memory if it is not webp
ByteBuffer buffer = isWebP ? MemoryUtil.memAlloc(0) : MemoryUtil.memAlloc(data.length).put(data).rewind();
// convert to RGBA
try (NativeImage image = isWebP ? WebPDecoder.toNativeImage(data, rgbaSwizzle) : NativeImage.read(buffer)) {
public StaticTextureProvider(String name, NativeImage image, @Nullable int[] rgbaSwizzle) throws IOException {
try {
mWidth = image.getWidth();
mHeight = image.getHeight();
if (mWidth > MAX_TEXTURE_SIZE || mHeight > MAX_TEXTURE_SIZE) {
Expand Down Expand Up @@ -72,7 +65,7 @@ public StaticTextureProvider(String name, byte[] data, boolean isWebP) {

try (image) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, image.pixels);
if (isWebP) {
if (rgbaSwizzle != null) {
// rearrange argb / 0rgb to rgba
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, rgbaSwizzle);
}
Expand All @@ -82,11 +75,9 @@ public StaticTextureProvider(String name, byte[] data, boolean isWebP) {
glGenerateMipmap(GL_TEXTURE_2D);
mRenderType = new SlideRenderType(mTexture);
mRecommendedName = name;
} catch (Throwable t) {
close();
throw new CompletionException(t);
} finally {
MemoryUtil.memFree(buffer);
} catch (IOException e) {
this.close();
throw e;
}
}

Expand Down

0 comments on commit 11ea4a6

Please sign in to comment.