Working towards 1.20.2-v3: Improve performance of map image loading
Signed-off-by: Irmo van den Berge <irmo.vandenberge@ziggo.nl>
This commit is contained in:
1 parent
366ad3c13e
commit
4ac9faf0bb
5 files changed
+70
-98
No files matched your search
+6
-1
@@ -8,7 +8,7 @@ plugins {
|
||||
val buildNumber = System.getenv("BUILD_NUMBER") ?: "NO-CI"
|
||||
|
||||
group = "com.bergerkiller.bukkit"
|
||||
version = "1.20.2-v2"
|
||||
version = "1.20.2-v3-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenLocal {
|
||||
@@ -67,6 +67,8 @@ dependencies {
|
||||
}
|
||||
// GSON isn't available in spigot versions prior to 1.8.1, shade it in order to keep 1.8 compatibility
|
||||
internal(libs.gson)
|
||||
// Color conversion helper library, https://github.com/bergerhealer/BKCommonLib-ColorConversionHelper
|
||||
api(libs.colorconversionhelper)
|
||||
|
||||
//
|
||||
// Optional provided dependencies that BKCommonLib can talk with
|
||||
@@ -152,6 +154,9 @@ tasks {
|
||||
this.testLogging {
|
||||
this.showStandardStreams = true
|
||||
}
|
||||
|
||||
// Uncomment to enable SIMD optimizations, to test performance of color conversion
|
||||
//jvmArgs("--add-modules", "jdk.incubator.vector");
|
||||
}
|
||||
|
||||
javadoc {
|
||||
|
||||
@@ -5,6 +5,7 @@ netty = "4.1.42.Final"
|
||||
log4j = "2.17.0"
|
||||
mountiplex = "2.99"
|
||||
regionchangetracker = "1.2"
|
||||
colorconversionhelper = "1.0"
|
||||
softdependencylib = "1.02"
|
||||
timings = "1.0.4"
|
||||
gson = "2.8.9"
|
||||
@@ -28,6 +29,7 @@ log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4
|
||||
log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" }
|
||||
mountiplex = { module = "com.bergerkiller.mountiplex:Mountiplex", version.ref = "mountiplex" }
|
||||
regionchangetracker = { module = "com.bergerkiller.bukkit.regionchangetracker:BKCommonLib-RegionChangeTracker-Core", version.ref = "regionchangetracker" }
|
||||
colorconversionhelper = { module = "com.bergerkiller.bukkit.colorconversionhelper:BKCommonLib-ColorConversionHelper", version.ref = "colorconversionhelper" }
|
||||
softdependency = { module = "com.bergerkiller.bukkit.softdependency:SoftDependency", version.ref = "softdependencylib" }
|
||||
timings = { module = "co.aikar:minecraft-timings", version.ref = "timings" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.bergerkiller.bukkit.common.internal.network.ProtocolLibPacketHandler;
|
||||
import com.bergerkiller.bukkit.common.internal.permissions.PermissionHandler;
|
||||
import com.bergerkiller.bukkit.common.internal.permissions.PermissionHandlerSelector;
|
||||
import com.bergerkiller.bukkit.common.map.MapColorPalette;
|
||||
import com.bergerkiller.bukkit.common.map.util.RGBColorToIntConversion;
|
||||
import com.bergerkiller.bukkit.common.offline.OfflineWorld;
|
||||
import com.bergerkiller.bukkit.common.protocol.PlayerGameInfo;
|
||||
import com.bergerkiller.bukkit.common.softdependency.SoftDependency;
|
||||
@@ -716,6 +717,11 @@ public class CommonPlugin extends PluginBase {
|
||||
// Do not do this if map displays are disabled.
|
||||
if (this.isMapDisplaysEnabled) {
|
||||
MapColorPalette.getColor(0, 0, 0);
|
||||
|
||||
// Log a message if java's experimental incubator vector api is used for loading images into map colors
|
||||
if (RGBColorToIntConversion.ABGR.isUsingSIMD()) {
|
||||
getLogger().log(Level.INFO, "JDK17+ incubator vector maths are enabled. Will use it for loading MapDisplay textures.");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize NBT early
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.bergerkiller.bukkit.common.internal.CommonBootstrap;
|
||||
import com.bergerkiller.bukkit.common.map.color.MCSDBubbleFormat;
|
||||
import com.bergerkiller.bukkit.common.map.color.MCSDGenBukkit;
|
||||
import com.bergerkiller.bukkit.common.map.color.MapColorSpaceData;
|
||||
import com.bergerkiller.bukkit.common.map.util.RGBColorToIntConversion;
|
||||
|
||||
/**
|
||||
* Additional functionality on top of Bukkit's MapPalette
|
||||
@@ -284,19 +285,17 @@ public class MapColorPalette {
|
||||
|
||||
// Obtain the color conversion type that has to be applied (RGB or BGR?)
|
||||
int type = imageBuf.getType();
|
||||
int byteStep = 4;
|
||||
ColorConverterType converterType = null;
|
||||
RGBColorToIntConversion converterType = null;
|
||||
if (type == BufferedImage.TYPE_INT_RGB) {
|
||||
converterType = ColorConverterType.RGB;
|
||||
converterType = RGBColorToIntConversion.RGB;
|
||||
} else if (type == BufferedImage.TYPE_INT_ARGB) {
|
||||
converterType = ColorConverterType.ARGB;
|
||||
converterType = RGBColorToIntConversion.ARGB;
|
||||
} else if (type == BufferedImage.TYPE_INT_BGR) {
|
||||
converterType = ColorConverterType.BGR;
|
||||
converterType = RGBColorToIntConversion.BGR;
|
||||
} else if (type == BufferedImage.TYPE_3BYTE_BGR) {
|
||||
converterType = ColorConverterType.BGR;
|
||||
byteStep = 3;
|
||||
converterType = RGBColorToIntConversion.BGR;
|
||||
} else if (type == BufferedImage.TYPE_4BYTE_ABGR) {
|
||||
converterType = ColorConverterType.ABGR;
|
||||
converterType = RGBColorToIntConversion.ABGR;
|
||||
}
|
||||
|
||||
// Incompatible backing buffer or color format; simply use int[] ARGB
|
||||
@@ -304,21 +303,24 @@ public class MapColorPalette {
|
||||
intPixels = new int[width * height];
|
||||
bytePixels = null;
|
||||
imageBuf.getRGB(0, 0, width, height, intPixels, 0, width);
|
||||
converterType = ColorConverterType.ARGB;
|
||||
converterType = RGBColorToIntConversion.ARGB;
|
||||
}
|
||||
|
||||
// Conversion method
|
||||
RGBColorToIntConversion.RGBToMapColorFunction converter;
|
||||
if (converterType.hasTransparency()) {
|
||||
converter = rgba -> (rgba & 0x80000000) != 0 ? COLOR_MAP_DATA.get(rgba & 0xFFFFFF)
|
||||
: COLOR_TRANSPARENT;
|
||||
} else {
|
||||
converter = COLOR_MAP_DATA::get;
|
||||
}
|
||||
|
||||
// Perform efficient conversion from RGB int to byte color codes
|
||||
byte[] result = new byte[width * height];
|
||||
if (bytePixels != null) {
|
||||
int index = 0;
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = converterType.convertBytes(bytePixels, index);
|
||||
index += byteStep;
|
||||
}
|
||||
converterType.byteBufferToMapColors(bytePixels, width * height, converter, result);
|
||||
} else {
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = converterType.convert(intPixels[i]);
|
||||
}
|
||||
converterType.intBufferToMapColors(intPixels, width * height, converter, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -430,12 +432,13 @@ public class MapColorPalette {
|
||||
graphics2D.dispose();
|
||||
}
|
||||
|
||||
// Conversion method
|
||||
RGBColorToIntConversion.RGBToMapColorFunction converter = rgba -> (rgba & 0x80000000) != 0
|
||||
? COLOR_MAP_DATA.get(rgba & 0xFFFFFF) : COLOR_TRANSPARENT;
|
||||
|
||||
// Convert back to map colors
|
||||
int[] intPixels = ((java.awt.image.DataBufferInt) outputImage.getRaster().getDataBuffer()).getData();
|
||||
ColorConverterType converterType = ColorConverterType.ARGB;
|
||||
for (int i = 0; i < outputLength; i++) {
|
||||
output[i] = converterType.convert(intPixels[i]);
|
||||
}
|
||||
RGBColorToIntConversion.ARGB.intBufferToMapColors(intPixels, outputLength, converter, output);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,78 +499,4 @@ public class MapColorPalette {
|
||||
public static IndexColorModel getIndexColorModel() {
|
||||
return COLOR_INDEX_MODEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used to convert raw color data into the
|
||||
* map color format without using an int[] buffer in between.
|
||||
* It is used when reading in images.
|
||||
*/
|
||||
private static abstract class ColorConverterType {
|
||||
public abstract byte convert(int color);
|
||||
public abstract byte convertBytes(byte[] buffer, int index);
|
||||
|
||||
public static final ColorConverterType RGB = new ColorConverterType() {
|
||||
@Override
|
||||
public byte convert(int color) {
|
||||
return COLOR_MAP_DATA.get(color >> 16, color >> 8, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte convertBytes(byte[] buffer, int index) {
|
||||
return COLOR_MAP_DATA.get(buffer[index], buffer[index + 1], buffer[index + 2]);
|
||||
}
|
||||
};
|
||||
|
||||
public static final ColorConverterType ARGB = new ColorConverterType() {
|
||||
@Override
|
||||
public byte convert(int color) {
|
||||
if ((color & 0x80000000) == 0) {
|
||||
return COLOR_TRANSPARENT;
|
||||
} else {
|
||||
return COLOR_MAP_DATA.get(color >> 16, color >> 8, color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte convertBytes(byte[] buffer, int index) {
|
||||
if ((buffer[index] & 0x80) == 0) {
|
||||
return COLOR_TRANSPARENT;
|
||||
} else {
|
||||
return COLOR_MAP_DATA.get(buffer[index + 1], buffer[index + 2], buffer[index + 3]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static final ColorConverterType BGR = new ColorConverterType() {
|
||||
@Override
|
||||
public byte convert(int color) {
|
||||
return COLOR_MAP_DATA.get(color, color >> 8, color >> 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte convertBytes(byte[] buffer, int index) {
|
||||
return COLOR_MAP_DATA.get(buffer[index + 2], buffer[index + 1], buffer[index]);
|
||||
}
|
||||
};
|
||||
|
||||
public static final ColorConverterType ABGR = new ColorConverterType() {
|
||||
@Override
|
||||
public byte convert(int color) {
|
||||
if ((color & 0x80000000) == 0) {
|
||||
return COLOR_TRANSPARENT;
|
||||
} else {
|
||||
return COLOR_MAP_DATA.get(color, color >> 8, color >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte convertBytes(byte[] buffer, int index) {
|
||||
if ((buffer[index] & 0x80) == 0) {
|
||||
return COLOR_TRANSPARENT;
|
||||
} else {
|
||||
return COLOR_MAP_DATA.get(buffer[index + 3], buffer[index + 2], buffer[index + 1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,7 @@ package com.bergerkiller.bukkit.common;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Image;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
@@ -14,6 +13,7 @@ import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.bergerkiller.bukkit.common.map.util.RGBColorToIntConversion;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -30,6 +30,36 @@ import com.bergerkiller.mountiplex.reflection.SafeField;
|
||||
|
||||
public class MapColorPaletteTest {
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void benchmark() throws Throwable {
|
||||
// Load image and initialize the palette by running it once
|
||||
Image image = ImageIO.read(new File("misc/map_test_bg.jpg"));
|
||||
|
||||
{
|
||||
BufferedImage temp = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = temp.createGraphics();
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.dispose();
|
||||
image = temp;
|
||||
}
|
||||
|
||||
System.out.println(RGBColorToIntConversion.SIMDLoader.getError());
|
||||
|
||||
MapColorPalette.convertImage(image);
|
||||
|
||||
MapDebugWindow.showMapForever(MapTexture.fromImage(image));
|
||||
|
||||
// Time further invocations
|
||||
int count = 10000;
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MapColorPalette.convertImage(image);
|
||||
}
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
System.out.println("Took: " + (((double) duration) / count) + " ms/op");
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void generateColorMap() {
|
||||
|
||||
Reference in new issue
Block a user