mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 23:47:09 +01:00
It's not a phase!
- Optimize collecting light section edges - Kinda an absurd amount of code, but I'm not sure how to parameterize by an axis without having capturing lambdas - Around 3-4x faster
This commit is contained in:
parent
2cced88749
commit
0c5995bad8
1 changed files with 151 additions and 34 deletions
|
@ -19,6 +19,7 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
|
import net.minecraft.world.level.lighting.LayerLightEventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: AO data
|
* TODO: AO data
|
||||||
|
@ -110,10 +111,8 @@ public class LightStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now actually do the collection.
|
// Now actually do the collection.
|
||||||
// TODO: Can this be done in parallel?
|
// TODO: Should this be done in parallel?
|
||||||
for (long section : sectionsToCollect) {
|
sectionsToCollect.forEach(this::collectSection);
|
||||||
collectSection(section);
|
|
||||||
}
|
|
||||||
|
|
||||||
requestedSections = null;
|
requestedSections = null;
|
||||||
});
|
});
|
||||||
|
@ -148,45 +147,138 @@ public class LightStorage {
|
||||||
var blockLight = lightEngine.getLayerListener(LightLayer.BLOCK);
|
var blockLight = lightEngine.getLayerListener(LightLayer.BLOCK);
|
||||||
var skyLight = lightEngine.getLayerListener(LightLayer.SKY);
|
var skyLight = lightEngine.getLayerListener(LightLayer.SKY);
|
||||||
|
|
||||||
var blockPos = new BlockPos.MutableBlockPos();
|
|
||||||
|
|
||||||
int xMin = SectionPos.sectionToBlockCoord(SectionPos.x(section));
|
|
||||||
int yMin = SectionPos.sectionToBlockCoord(SectionPos.y(section));
|
|
||||||
int zMin = SectionPos.sectionToBlockCoord(SectionPos.z(section));
|
|
||||||
|
|
||||||
var sectionPos = SectionPos.of(section);
|
|
||||||
var blockData = blockLight.getDataLayerData(sectionPos);
|
|
||||||
var skyData = skyLight.getDataLayerData(sectionPos);
|
|
||||||
|
|
||||||
int index = indexForSection(section);
|
int index = indexForSection(section);
|
||||||
|
|
||||||
changed.set(index);
|
changed.set(index);
|
||||||
|
|
||||||
long ptr = arena.indexToPointer(index);
|
long ptr = arena.indexToPointer(index);
|
||||||
|
|
||||||
// Not sure of a way to iterate over the surface of a cube, so branch in the inner loop to take the fast path.
|
// Zero it out first. This is basically free and makes it easier to handle missing sections later.
|
||||||
// Adding the fast path is about 8x faster than having only the slow path.
|
MemoryUtil.memSet(ptr, 0, SECTION_SIZE_BYTES);
|
||||||
// There's still room for optimization, as the slow path takes about 3x the cpu time as the fast path despite
|
|
||||||
// being called an order of magnitude less.
|
|
||||||
for (int y = -1; y < 17; y++) {
|
|
||||||
for (int z = -1; z < 17; z++) {
|
|
||||||
for (int x = -1; x < 17; x++) {
|
|
||||||
if (x == -1 || y == -1 || z == -1 || x == 16 || y == 16 || z == 16) {
|
|
||||||
// Slow path, collect the surface of our section.
|
|
||||||
blockPos.set(xMin + x, yMin + y, zMin + z);
|
|
||||||
var block = blockLight.getLightValue(blockPos);
|
|
||||||
var sky = skyLight.getLightValue(blockPos);
|
|
||||||
|
|
||||||
write(ptr, x, y, z, block, sky);
|
collectCenter(blockLight, skyLight, ptr, section);
|
||||||
} else {
|
|
||||||
// Fast path, read directly from the data layer for the main section.
|
|
||||||
// Would be nice to move the null check elsewhere.
|
|
||||||
var block = blockData == null ? 0 : blockData.get(x, y, z);
|
|
||||||
var sky = skyData == null ? 0 : skyData.get(x, y, z);
|
|
||||||
|
|
||||||
write(ptr, x, y, z, block, sky);
|
for (SectionEdge i : SectionEdge.values()) {
|
||||||
|
collectYZPlane(blockLight, skyLight, ptr, SectionPos.offset(section, i.sectionOffset, 0, 0), i);
|
||||||
|
collectXZPlane(blockLight, skyLight, ptr, SectionPos.offset(section, 0, i.sectionOffset, 0), i);
|
||||||
|
collectXYPlane(blockLight, skyLight, ptr, SectionPos.offset(section, 0, 0, i.sectionOffset), i);
|
||||||
|
|
||||||
|
for (SectionEdge j : SectionEdge.values()) {
|
||||||
|
collectXStrip(blockLight, skyLight, ptr, SectionPos.offset(section, 0, i.sectionOffset, j.sectionOffset), i, j);
|
||||||
|
collectYStrip(blockLight, skyLight, ptr, SectionPos.offset(section, i.sectionOffset, 0, j.sectionOffset), i, j);
|
||||||
|
collectZStrip(blockLight, skyLight, ptr, SectionPos.offset(section, i.sectionOffset, j.sectionOffset, 0), i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectCorners(blockLight, skyLight, ptr, section);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectXStrip(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge y, SectionEdge z) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
write(ptr, x, y.relative, z.relative, blockData.get(x, y.pos, z.pos), skyData.get(x, y.pos, z.pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectYStrip(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge x, SectionEdge z) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
write(ptr, x.relative, y, z.relative, blockData.get(x.pos, y, z.pos), skyData.get(x.pos, y, z.pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectZStrip(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge x, SectionEdge y) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
write(ptr, x.relative, y.relative, z, blockData.get(x.pos, y.pos, z), skyData.get(x.pos, y.pos, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectYZPlane(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge x) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
write(ptr, x.relative, y, z, blockData.get(x.pos, y, z), skyData.get(x.pos, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectXZPlane(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge y) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
write(ptr, x, y.relative, z, blockData.get(x, y.pos, z), skyData.get(x, y.pos, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectXYPlane(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge z) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
write(ptr, x, y, z.relative, blockData.get(x, y, z.pos), skyData.get(x, y, z.pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectCenter(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section) {
|
||||||
|
var pos = SectionPos.of(section);
|
||||||
|
var blockData = blockLight.getDataLayerData(pos);
|
||||||
|
var skyData = skyLight.getDataLayerData(pos);
|
||||||
|
if (blockData == null || skyData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
write(ptr, x, y, z, blockData.get(x, y, z), skyData.get(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectCorners(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section) {
|
||||||
|
var blockPos = new BlockPos.MutableBlockPos();
|
||||||
|
int xMin = SectionPos.sectionToBlockCoord(SectionPos.x(section));
|
||||||
|
int yMin = SectionPos.sectionToBlockCoord(SectionPos.y(section));
|
||||||
|
int zMin = SectionPos.sectionToBlockCoord(SectionPos.z(section));
|
||||||
|
|
||||||
|
for (SectionEdge x : SectionEdge.values()) {
|
||||||
|
for (SectionEdge y : SectionEdge.values()) {
|
||||||
|
for (SectionEdge z : SectionEdge.values()) {
|
||||||
|
blockPos.set(x.relative + xMin, y.relative + yMin, z.relative + zMin);
|
||||||
|
write(ptr, x.relative, y.relative, z.relative, blockLight.getLightValue(blockPos), skyLight.getLightValue(blockPos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,4 +356,29 @@ public class LightStorage {
|
||||||
// TODO: incremental lut updates
|
// TODO: incremental lut updates
|
||||||
return LightLut.buildLut(section2ArenaIndex);
|
return LightLut.buildLut(section2ArenaIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum SectionEdge {
|
||||||
|
LOW(15, -1, -1),
|
||||||
|
HIGH(0, 16, 1),
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position in the section to collect.
|
||||||
|
*/
|
||||||
|
private final int pos;
|
||||||
|
/**
|
||||||
|
* The position relative to the main section.
|
||||||
|
*/
|
||||||
|
private final int relative;
|
||||||
|
/**
|
||||||
|
* The offset to the neighboring section.
|
||||||
|
*/
|
||||||
|
private final int sectionOffset;
|
||||||
|
|
||||||
|
SectionEdge(int pos, int relative, int sectionOffset) {
|
||||||
|
this.pos = pos;
|
||||||
|
this.relative = relative;
|
||||||
|
this.sectionOffset = sectionOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue