aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1065-Reduce-work-done-in-CraftMapCanvas.drawImage-by-limi.patch
blob: 81c7b52685990b9b63a8d1f6a69110bd6ee697d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Barnaby <22575741+barnabwhy@users.noreply.github.com>
Date: Sat, 29 Jun 2024 12:06:51 +0100
Subject: [PATCH] Reduce work done in CraftMapCanvas.drawImage by limiting size
 of image and using System.arraycopy instead of for loops and use bitwise
 operations to do bounds checks.


diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java
index ff59f759669620795ef355c988b664bdcda39f52..a5e98571d6d83390761c11e28a0bc3c4415799cd 100644
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java
@@ -91,12 +91,41 @@ public class CraftMapCanvas implements MapCanvas {
 
     @Override
     public void drawImage(int x, int y, Image image) {
-        byte[] bytes = MapPalette.imageToBytes(image);
-        for (int x2 = 0; x2 < image.getWidth(null); ++x2) {
-            for (int y2 = 0; y2 < image.getHeight(null); ++y2) {
-                this.setPixel(x + x2, y + y2, bytes[y2 * image.getWidth(null) + x2]);
+        // Paper start - Reduce work done by limiting size of image and using System.arraycopy
+        int width = 128 - x;
+        int height = 128 - y;
+        if (image.getHeight(null) < height)
+            height = image.getHeight(null);
+
+        // Create a subimage if the image is larger than the max allowed size
+        java.awt.image.BufferedImage temp;
+        if (image.getWidth(null) >= width && image instanceof java.awt.image.BufferedImage bImage) {
+            // If the image is larger than the max allowed size, get a subimage, otherwise use the image as is
+            if (image.getWidth(null) > width || image.getHeight(null) > height) {
+                temp = bImage.getSubimage(0, 0, width, height);
+            } else {
+                temp = bImage;
             }
+        } else {
+            temp = new java.awt.image.BufferedImage(width, height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
+            java.awt.Graphics2D graphics = temp.createGraphics();
+            graphics.drawImage(image, 0, 0, null);
+            graphics.dispose();
         }
+
+        byte[] bytes = MapPalette.imageToBytes(temp);
+        
+        // Since we now control the size of the image, we can safely use System.arraycopy
+        // If x is 0, we can just copy the entire image as width is 128 and height is <=(128-y)
+        if (x == 0) {
+            System.arraycopy(bytes, 0, this.buffer, y * 128, width * height);
+            return;
+        }
+
+        for (int y2 = 0; y2 < height; ++y2) {
+            System.arraycopy(bytes, 0, this.buffer, (y + y2) * 128 + x, width);
+        }
+        // Paper end
     }
 
     @Override
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
index 0cbbd915631904fe8c6effefb92895422b33eff6..cf0920e5f84b35647882fb963e9972af4e8427e0 100644
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
@@ -23,8 +23,10 @@ public class CraftMapRenderer extends MapRenderer {
     @Override
     public void render(MapView map, MapCanvas canvas, Player player) {
         // Map
-        for (int x = 0; x < 128; ++x) {
-            for (int y = 0; y < 128; ++y) {
+        // Paper start - Swap inner and outer loops here to (theoretically) improve cache locality
+        for (int y = 0; y < 128; ++y) {
+            for (int x = 0; x < 128; ++x) {
+        // Paper end
                 canvas.setPixel(x, y, this.worldMap.colors[y * 128 + x]);
             }
         }