Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.BlockDestructionProgress;
import net.minecraft.util.Mth;
import net.minecraft.util.profiling.Profiler;
Expand Down Expand Up @@ -210,7 +209,7 @@ public void setupTerrain(Camera camera,
this.lastCameraYaw = yaw;

if (cameraLocationChanged || fogDistanceChanged || cameraAngleChanged || cameraProjectionChanged) {
this.renderSectionManager.markGraphDirty();
this.renderSectionManager.notifyChangedCamera();
}

this.lastFogParameters = fogParameters;
Expand All @@ -227,16 +226,14 @@ public void setupTerrain(Camera camera,
int maxChunkUpdates = updateChunksImmediately ? this.renderDistance : 1;

for (int i = 0; i < maxChunkUpdates; i++) {
if (this.renderSectionManager.needsUpdate()) {
profiler.popPush("chunk_render_lists");
profiler.popPush("chunk_render_lists");

this.renderSectionManager.update(camera, viewport, fogParameters, spectator);
}
this.renderSectionManager.updateRenderLists(camera, viewport, fogParameters, spectator, updateChunksImmediately);

profiler.popPush("chunk_update");

this.renderSectionManager.cleanupAndFlip();
this.renderSectionManager.updateChunks(updateChunksImmediately);
this.renderSectionManager.updateChunks(viewport, updateChunksImmediately);

profiler.popPush("chunk_upload");

Expand Down Expand Up @@ -356,9 +353,8 @@ private void renderBlockEntities(PoseStack matrices,

while (renderSectionIterator.hasNext()) {
var renderSectionId = renderSectionIterator.nextByteAsInt();
var renderSection = renderRegion.getSection(renderSectionId);

var blockEntities = renderSection.getCulledBlockEntities();
var blockEntities = renderRegion.getCulledBlockEntities(renderSectionId);

if (blockEntities == null) {
continue;
Expand All @@ -383,7 +379,7 @@ private void renderGlobalBlockEntities(PoseStack matrices,
LocalPlayer player,
LocalBooleanRef isGlowing) {
for (var renderSection : this.renderSectionManager.getSectionsWithGlobalEntities()) {
var blockEntities = renderSection.getGlobalBlockEntities();
var blockEntities = renderSection.getRegion().getGlobalBlockEntities(renderSection.getSectionIndex());

if (blockEntities == null) {
continue;
Expand Down Expand Up @@ -457,9 +453,7 @@ public void iterateVisibleBlockEntities(Consumer<BlockEntity> blockEntityConsume

while (renderSectionIterator.hasNext()) {
var renderSectionId = renderSectionIterator.nextByteAsInt();
var renderSection = renderRegion.getSection(renderSectionId);

var blockEntities = renderSection.getCulledBlockEntities();
var blockEntities = renderRegion.getCulledBlockEntities(renderSectionId);

if (blockEntities == null) {
continue;
Expand All @@ -472,7 +466,7 @@ public void iterateVisibleBlockEntities(Consumer<BlockEntity> blockEntityConsume
}

for (var renderSection : this.renderSectionManager.getSectionsWithGlobalEntities()) {
var blockEntities = renderSection.getGlobalBlockEntities();
var blockEntities = renderSection.getRegion().getGlobalBlockEntities(renderSection.getSectionIndex());

if (blockEntities == null) {
continue;
Expand All @@ -485,10 +479,13 @@ public void iterateVisibleBlockEntities(Consumer<BlockEntity> blockEntityConsume
}

// the volume of a section multiplied by the number of sections to be checked at most
private static final double MAX_ENTITY_CHECK_VOLUME = 16 * 16 * 16 * 15;
private static final double MAX_ENTITY_CHECK_VOLUME = 16 * 16 * 16 * 50;

/**
* Returns whether the entity intersects with any visible chunks in the graph.
*
* Note that this method assumes the entity is within the frustum. It does not perform a frustum check.
*
* @return True if the entity is visible, otherwise false
*/
public <T extends Entity, S extends EntityRenderState> boolean isEntityVisible(EntityRenderer<T, S> renderer, T entity) {
Expand All @@ -506,7 +503,7 @@ public <T extends Entity, S extends EntityRenderState> boolean isEntityVisible(E
// bail on very large entities to avoid checking many sections
double entityVolume = (bb.maxX - bb.minX) * (bb.maxY - bb.minY) * (bb.maxZ - bb.minZ);
if (entityVolume > MAX_ENTITY_CHECK_VOLUME) {
// TODO: do a frustum check instead, even large entities aren't visible if they're outside the frustum
// large entities are only frustum tested, their sections are not checked for visibility
return true;
}

Expand All @@ -520,48 +517,28 @@ public boolean isBoxVisible(double x1, double y1, double z1, double x2, double y
return true;
}

int minX = SectionPos.posToSectionCoord(x1 - 0.5D);
int minY = SectionPos.posToSectionCoord(y1 - 0.5D);
int minZ = SectionPos.posToSectionCoord(z1 - 0.5D);

int maxX = SectionPos.posToSectionCoord(x2 + 0.5D);
int maxY = SectionPos.posToSectionCoord(y2 + 0.5D);
int maxZ = SectionPos.posToSectionCoord(z2 + 0.5D);

for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
for (int y = minY; y <= maxY; y++) {
if (this.renderSectionManager.isSectionVisible(x, y, z)) {
return true;
}
}
}
}

return false;
return this.renderSectionManager.isBoxVisible(x1, y1, z1, x2, y2, z2);
}

public String getChunksDebugString() {
// C: visible/total D: distance
// TODO: add dirty and queued counts
return String.format("C: %d/%d D: %d", this.renderSectionManager.getVisibleChunkCount(), this.renderSectionManager.getTotalSections(), this.renderDistance);
return this.renderSectionManager.getChunksDebugString();
}

/**
* Schedules chunk rebuilds for all chunks in the specified block region.
*/
public void scheduleRebuildForBlockArea(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean important) {
this.scheduleRebuildForChunks(minX >> 4, minY >> 4, minZ >> 4, maxX >> 4, maxY >> 4, maxZ >> 4, important);
public void scheduleRebuildForBlockArea(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean playerChanged) {
this.scheduleRebuildForChunks(minX >> 4, minY >> 4, minZ >> 4, maxX >> 4, maxY >> 4, maxZ >> 4, playerChanged);
}

/**
* Schedules chunk rebuilds for all chunks in the specified chunk region.
*/
public void scheduleRebuildForChunks(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean important) {
public void scheduleRebuildForChunks(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean playerChanged) {
for (int chunkX = minX; chunkX <= maxX; chunkX++) {
for (int chunkY = minY; chunkY <= maxY; chunkY++) {
for (int chunkZ = minZ; chunkZ <= maxZ; chunkZ++) {
this.scheduleRebuildForChunk(chunkX, chunkY, chunkZ, important);
this.scheduleRebuildForChunk(chunkX, chunkY, chunkZ, playerChanged);
}
}
}
Expand All @@ -570,8 +547,8 @@ public void scheduleRebuildForChunks(int minX, int minY, int minZ, int maxX, int
/**
* Schedules a chunk rebuild for the render belonging to the given chunk section position.
*/
public void scheduleRebuildForChunk(int x, int y, int z, boolean important) {
this.renderSectionManager.scheduleRebuild(x, y, z, important);
public void scheduleRebuildForChunk(int x, int y, int z, boolean playerChanged) {
this.renderSectionManager.scheduleRebuild(x, y, z, playerChanged);
}

public Collection<String> getDebugStrings() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,25 @@ public static boolean isRebuildWithSort(int type) {
return (isRebuild(type) || isInitialBuild(type)) && isSort(type);
}

public static TaskQueueType getQueueType(int type, TaskQueueType importantRebuildQueueType) {
if (isInitialBuild(type)) {
return TaskQueueType.INITIAL_BUILD;
}
public static DeferMode getDeferMode(int type, DeferMode importantRebuildDeferMode) {
if (isImportant(type)) {
if (isRebuild(type)) {
return importantRebuildQueueType;
return importantRebuildDeferMode;
} else { // implies important sort task
return TaskQueueType.ZERO_FRAME_DEFER;
return DeferMode.ZERO_FRAMES;
}
} else {
return TaskQueueType.ALWAYS_DEFER;
return DeferMode.ALWAYS;
}
}

public static int getPriorityValue(int type) {
if (isInitialBuild(type)) {
return 0;
}
if (isRebuild(type)) {
return 1;
}
return 2; // sort
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,22 @@
import net.minecraft.network.chat.Component;

public enum DeferMode implements TextProvider {
ALWAYS("sodium.options.defer_chunk_updates.always", TaskQueueType.ALWAYS_DEFER),
ONE_FRAME("sodium.options.defer_chunk_updates.one_frame", TaskQueueType.ONE_FRAME_DEFER),
ZERO_FRAMES("sodium.options.defer_chunk_updates.zero_frames", TaskQueueType.ZERO_FRAME_DEFER);
ALWAYS("sodium.options.defer_chunk_updates.always"),
ONE_FRAME("sodium.options.defer_chunk_updates.one_frame"),
ZERO_FRAMES("sodium.options.defer_chunk_updates.zero_frames");

private final Component name;
private final TaskQueueType importantRebuildQueueType;

DeferMode(String name, TaskQueueType importantRebuildQueueType) {
DeferMode(String name) {
this.name = Component.translatable(name);
this.importantRebuildQueueType = importantRebuildQueueType;
}

@Override
public Component getLocalizedName() {
return this.name;
}

public TaskQueueType getImportantRebuildQueueType() {
return this.importantRebuildQueueType;
public boolean allowsUnlimitedUploadDuration() {
return this == ZERO_FRAMES;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData;
import net.caffeinemc.mods.sodium.client.util.task.CancellationToken;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -31,7 +28,7 @@ public class RenderSection {
private long visibilityData = VisibilityEncoding.NULL;

private int incomingDirections;
private int lastVisibleFrame = -1;
private int lastVisibleSearchToken = -1;

private int adjacentMask;
public RenderSection
Expand All @@ -42,13 +39,7 @@ public class RenderSection {
adjacentWest,
adjacentEast;


// Rendering State
private boolean built = false; // merge with the flags?
private int flags = RenderSectionFlags.NONE;
private BlockEntity @Nullable[] globalBlockEntities;
private BlockEntity @Nullable[] culledBlockEntities;
private TextureAtlasSprite @Nullable[] animatedSprites;
@Nullable
private TranslucentData translucentData;

Expand Down Expand Up @@ -150,32 +141,22 @@ public boolean setInfo(@Nullable BuiltSectionInfo info) {
}

private boolean setRenderState(@NotNull BuiltSectionInfo info) {
var prevBuilt = this.built;
var prevFlags = this.flags;
var prevFlags = this.region.getSectionFlags(this.sectionIndex);
var prevVisibilityData = this.visibilityData;

this.built = true;
this.flags = info.flags;
this.region.setSectionRenderState(this.sectionIndex, info);
this.visibilityData = info.visibilityData;

this.globalBlockEntities = info.globalBlockEntities;
this.culledBlockEntities = info.culledBlockEntities;
this.animatedSprites = info.animatedSprites;

// the section is marked as having received graph-relevant changes if it's build state, flags, or connectedness has changed.
// the entities and sprites don't need to be checked since whether they exist is encoded in the flags.
return !prevBuilt || prevFlags != this.flags || prevVisibilityData != this.visibilityData;
return prevFlags != this.region.getSectionFlags(this.sectionIndex) || prevVisibilityData != this.visibilityData;
}

private boolean clearRenderState() {
var wasBuilt = this.built;
var wasBuilt = this.isBuilt();

this.built = false;
this.flags = RenderSectionFlags.NONE;
this.region.clearSectionRenderState(this.sectionIndex);
this.visibilityData = VisibilityEncoding.NULL;
this.globalBlockEntities = null;
this.culledBlockEntities = null;
this.animatedSprites = null;

// changes to data if it moves from built to not built don't matter, so only build state changes matter
return wasBuilt;
Expand Down Expand Up @@ -217,14 +198,6 @@ public int getOriginZ() {
return this.chunkZ << 4;
}

/**
* @return The squared distance from the center of this chunk in the level to the center of the block position
* given by {@param pos}
*/
public float getSquaredDistance(BlockPos pos) {
return this.getSquaredDistance(pos.getX() + 0.5f, pos.getY() + 0.5f, pos.getZ() + 0.5f);
}

/**
* @return The squared distance from the center of this chunk to the given block position
*/
Expand Down Expand Up @@ -282,7 +255,7 @@ public String toString() {
}

public boolean isBuilt() {
return this.built;
return (this.region.getSectionFlags(this.sectionIndex) & RenderSectionFlags.MASK_IS_BUILT) != 0;
}

public int getSectionIndex() {
Expand All @@ -293,12 +266,16 @@ public RenderRegion getRegion() {
return this.region;
}

public void setLastVisibleFrame(int frame) {
this.lastVisibleFrame = frame;
public boolean needsRender() {
return this.region.sectionNeedsRender(this.sectionIndex);
}

public int getLastVisibleFrame() {
return this.lastVisibleFrame;
public void setLastVisibleSearchToken(int frame) {
this.lastVisibleSearchToken = frame;
}

public int getLastVisibleSearchToken() {
return this.lastVisibleSearchToken;
}

public int getIncomingDirections() {
Expand All @@ -313,42 +290,13 @@ public void setIncomingDirections(int directions) {
this.incomingDirections = directions;
}

/**
* Returns a bitfield containing the {@link RenderSectionFlags} for this built section.
*/
public int getFlags() {
return this.flags;
}

/**
* Returns the occlusion culling data which determines this chunk's connectedness on the visibility graph.
*/
public long getVisibilityData() {
return this.visibilityData;
}

/**
* Returns the collection of animated sprites contained by this rendered chunk section.
*/
public TextureAtlasSprite @Nullable[] getAnimatedSprites() {
return this.animatedSprites;
}

/**
* Returns the collection of block entities contained by this rendered chunk.
*/
public BlockEntity @Nullable[] getCulledBlockEntities() {
return this.culledBlockEntities;
}

/**
* Returns the collection of block entities contained by this rendered chunk, which are not part of its culling
* volume. These entities should always be rendered regardless of the render being visible in the frustum.
*/
public BlockEntity @Nullable[] getGlobalBlockEntities() {
return this.globalBlockEntities;
}

public @Nullable CancellationToken getTaskCancellationToken() {
return this.taskCancellationToken;
}
Expand Down
Loading