SectionRenderDispatcher.java

net.minecraft.client.renderer.chunk.SectionRenderDispatcher

信息

  • 全限定名:net.minecraft.client.renderer.chunk.SectionRenderDispatcher
  • 类型:public class
  • 包:net.minecraft.client.renderer.chunk
  • 源码路径:src/main/java/net/minecraft/client/renderer/chunk/SectionRenderDispatcher.java
  • 起始行号:L46
  • 职责:

    TODO

字段/常量

  • compileQueue

    • 类型: CompileTaskDynamicQueue
    • 修饰符: private final
    • 源码定位: L47
    • 说明:

      TODO

  • fixedBuffers

    • 类型: SectionBufferBuilderPack
    • 修饰符: private final
    • 源码定位: L48
    • 说明:

      TODO

  • bufferPool

    • 类型: SectionBufferBuilderPool
    • 修饰符: private final
    • 源码定位: L49
    • 说明:

      TODO

  • closed

    • 类型: boolean
    • 修饰符: private volatile
    • 源码定位: L50
    • 说明:

      TODO

  • executor

    • 类型: TracingExecutor
    • 修饰符: private final
    • 源码定位: L51
    • 说明:

      TODO

  • level

    • 类型: ClientLevel
    • 修饰符: private
    • 源码定位: L52
    • 说明:

      TODO

  • renderer

    • 类型: LevelRenderer
    • 修饰符: private final
    • 源码定位: L53
    • 说明:

      TODO

  • cameraPosition

    • 类型: AtomicReference<Vec3>
    • 修饰符: private final
    • 源码定位: L54
    • 说明:

      TODO

  • sectionCompiler

    • 类型: SectionCompiler
    • 修饰符: private
    • 源码定位: L55
    • 说明:

      TODO

  • chunkUberBuffers

    • 类型: Map<ChunkSectionLayer,SectionRenderDispatcher.SectionUberBuffers>
    • 修饰符: private final
    • 源码定位: L56
    • 说明:

      TODO

  • copyLock

    • 类型: ReentrantLock
    • 修饰符: private final
    • 源码定位: L57
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.RenderSection

    • 类型: class
    • 修饰符: public
    • 源码定位: L221
    • 说明:

      TODO

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.RenderSection.CompileTask

    • 类型: class
    • 修饰符: public abstract
    • 源码定位: L490
    • 说明:

      TODO

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult

    • 类型: enum
    • 修饰符: public static
    • 源码定位: L518
    • 说明:

      TODO

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.RenderSection.RebuildTask

    • 类型: class
    • 修饰符: private
    • 源码定位: L525
    • 说明:

      TODO

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.RenderSection.ResortTransparencyTask

    • 类型: class
    • 修饰符: private
    • 源码定位: L615
    • 说明:

      TODO

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.RenderSectionBufferSlice

    • 类型: record
    • 修饰符: public
    • 源码定位: L682
    • 说明:

      TODO

  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher.SectionUberBuffers

    • 类型: record
    • 修饰符: private
    • 源码定位: L686
    • 说明:

      TODO

构造器

public SectionRenderDispatcher(ClientLevel level, LevelRenderer renderer, TracingExecutor executor, RenderBuffers renderBuffers, SectionCompiler sectionCompiler) @ L59

  • 构造器名:SectionRenderDispatcher
  • 源码定位:L59
  • 修饰符:public

参数:

  • level: ClientLevel
  • renderer: LevelRenderer
  • executor: TracingExecutor
  • renderBuffers: RenderBuffers
  • sectionCompiler: SectionCompiler

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void setLevel(ClientLevel level, SectionCompiler sectionCompiler) @ L89

  • 方法名:setLevel
  • 源码定位:L89
  • 返回类型:void
  • 修饰符:public

参数:

  • level: ClientLevel
  • sectionCompiler: SectionCompiler

说明:

TODO

private void runTask() @ L94

  • 方法名:runTask
  • 源码定位:L94
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public void setCameraPosition(Vec3 cameraPosition) @ L118

  • 方法名:setCameraPosition
  • 源码定位:L118
  • 返回类型:void
  • 修饰符:public

参数:

  • cameraPosition: Vec3

说明:

TODO

public SectionRenderDispatcher.RenderSectionBufferSlice getRenderSectionSlice(SectionMesh sectionMesh, ChunkSectionLayer layer) @ L122

  • 方法名:getRenderSectionSlice
  • 源码定位:L122
  • 返回类型:SectionRenderDispatcher.RenderSectionBufferSlice
  • 修饰符:public

参数:

  • sectionMesh: SectionMesh
  • layer: ChunkSectionLayer

说明:

TODO

public void lock() @ L143

  • 方法名:lock
  • 源码定位:L143
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void unlock() @ L147

  • 方法名:unlock
  • 源码定位:L147
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void uploadGlobalGeomBuffersToGPU() @ L151

  • 方法名:uploadGlobalGeomBuffersToGPU
  • 源码定位:L151
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void rebuildSectionSync(SectionRenderDispatcher.RenderSection section, RenderRegionCache cache) @ L169

  • 方法名:rebuildSectionSync
  • 源码定位:L169
  • 返回类型:void
  • 修饰符:public

参数:

  • section: SectionRenderDispatcher.RenderSection
  • cache: RenderRegionCache

说明:

TODO

public void schedule(SectionRenderDispatcher.RenderSection.CompileTask task) @ L173

  • 方法名:schedule
  • 源码定位:L173
  • 返回类型:void
  • 修饰符:public

参数:

  • task: SectionRenderDispatcher.RenderSection.CompileTask

说明:

TODO

public void clearCompileQueue() @ L180

  • 方法名:clearCompileQueue
  • 源码定位:L180
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public boolean isQueueEmpty() @ L184

  • 方法名:isQueueEmpty
  • 源码定位:L184
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void dispose() @ L188

  • 方法名:dispose
  • 源码定位:L188
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public String getStats() @ L205

  • 方法名:getStats
  • 源码定位:L205
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public int getCompileQueueSize() @ L210

  • 方法名:getCompileQueueSize
  • 源码定位:L210
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int getFreeBufferCount() @ L215

  • 方法名:getFreeBufferCount
  • 源码定位:L215
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class SectionRenderDispatcher {
    private final CompileTaskDynamicQueue compileQueue = new CompileTaskDynamicQueue();
    private final SectionBufferBuilderPack fixedBuffers;
    private final SectionBufferBuilderPool bufferPool;
    private volatile boolean closed;
    private final TracingExecutor executor;
    private ClientLevel level;
    private final LevelRenderer renderer;
    private final AtomicReference<Vec3> cameraPosition = new AtomicReference<>(Vec3.ZERO);
    private SectionCompiler sectionCompiler;
    private final Map<ChunkSectionLayer, SectionRenderDispatcher.SectionUberBuffers> chunkUberBuffers;
    private final ReentrantLock copyLock = new ReentrantLock();
 
    public SectionRenderDispatcher(
        ClientLevel level, LevelRenderer renderer, TracingExecutor executor, RenderBuffers renderBuffers, SectionCompiler sectionCompiler
    ) {
        this.level = level;
        this.renderer = renderer;
        this.fixedBuffers = renderBuffers.fixedBufferPack();
        this.bufferPool = renderBuffers.sectionBufferPool();
        this.executor = executor;
        this.sectionCompiler = sectionCompiler;
        int vertexBufferHeapSize = 134217728;
        int indexBufferHeapSize = 33554432;
        int vertexStagingBufferSize = 33554432;
        int indexStagingBufferSize = 2097152;
        GpuDevice gpuDevice = RenderSystem.getDevice();
        GraphicsWorkarounds workarounds = GraphicsWorkarounds.get(gpuDevice);
        this.chunkUberBuffers = Util.makeEnumMap(
            ChunkSectionLayer.class,
            layer -> {
                VertexFormat vertexFormat = layer.pipeline().getVertexFormat();
                UberGpuBuffer<SectionMesh> vertexUberBuffer = new UberGpuBuffer<>(
                    layer.label(), 32, 134217728, vertexFormat.getVertexSize(), gpuDevice, 33554432, workarounds
                );
                UberGpuBuffer<SectionMesh> indexUberBuffer = layer == ChunkSectionLayer.TRANSLUCENT
                    ? new UberGpuBuffer<>(layer.label(), 64, 33554432, 8, gpuDevice, 2097152, workarounds)
                    : null;
                return new SectionRenderDispatcher.SectionUberBuffers(vertexUberBuffer, indexUberBuffer);
            }
        );
    }
 
    public void setLevel(ClientLevel level, SectionCompiler sectionCompiler) {
        this.level = level;
        this.sectionCompiler = sectionCompiler;
    }
 
    private void runTask() {
        if (!this.closed) {
            SectionRenderDispatcher.RenderSection.CompileTask task = this.compileQueue.poll(this.cameraPosition.get());
            if (task != null && !task.isCompleted.get() && !task.isCancelled.get()) {
                try {
                    SectionBufferBuilderPack buffer = Objects.requireNonNull(this.bufferPool.acquire());
                    SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult result = task.doTask(buffer);
                    task.isCompleted.set(true);
                    if (result == SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.SUCCESSFUL) {
                        buffer.clearAll();
                    } else {
                        buffer.discardAll();
                    }
 
                    this.bufferPool.release(buffer);
                } catch (NullPointerException var4) {
                    this.compileQueue.add(task);
                } catch (Exception var5) {
                    Minecraft.getInstance().delayCrash(CrashReport.forThrowable(var5, "Batching sections"));
                }
            }
        }
    }
 
    public void setCameraPosition(Vec3 cameraPosition) {
        this.cameraPosition.set(cameraPosition);
    }
 
    public SectionRenderDispatcher.@Nullable RenderSectionBufferSlice getRenderSectionSlice(SectionMesh sectionMesh, ChunkSectionLayer layer) {
        SectionRenderDispatcher.SectionUberBuffers uberBuffers = this.chunkUberBuffers.get(layer);
        TlsfAllocator.Allocation vertexSlice = uberBuffers.vertexBuffer.getAllocation(sectionMesh);
        if (vertexSlice == null) {
            return null;
        } else {
            long vertexBufferOffset = vertexSlice.getOffsetFromHeap();
            TlsfAllocator.Allocation indexSlice = uberBuffers.indexBuffer != null ? uberBuffers.indexBuffer.getAllocation(sectionMesh) : null;
            long indexBufferOffset = 0L;
            GpuBuffer indexBuffer = null;
            if (indexSlice != null) {
                indexBufferOffset = indexSlice.getOffsetFromHeap();
                indexBuffer = uberBuffers.indexBuffer.getGpuBuffer(indexSlice);
            }
 
            return new SectionRenderDispatcher.RenderSectionBufferSlice(
                uberBuffers.vertexBuffer.getGpuBuffer(vertexSlice), vertexBufferOffset, indexBuffer, indexBufferOffset
            );
        }
    }
 
    public void lock() {
        this.copyLock.lock();
    }
 
    public void unlock() {
        this.copyLock.unlock();
    }
 
    public void uploadGlobalGeomBuffersToGPU() {
        CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder();
        boolean performedBufferResize = false;
 
        for (SectionRenderDispatcher.SectionUberBuffers buffers : this.chunkUberBuffers.values()) {
            UberGpuBuffer<SectionMesh> vertexBuffer = buffers.vertexBuffer;
            if (performedBufferResize) {
                break;
            }
 
            performedBufferResize = vertexBuffer.uploadStagedAllocations(RenderSystem.getDevice(), commandEncoder);
            UberGpuBuffer<SectionMesh> indexBuffer = buffers.indexBuffer;
            if (indexBuffer != null) {
                indexBuffer.uploadStagedAllocations(RenderSystem.getDevice(), commandEncoder);
            }
        }
    }
 
    public void rebuildSectionSync(SectionRenderDispatcher.RenderSection section, RenderRegionCache cache) {
        section.compileSync(cache);
    }
 
    public void schedule(SectionRenderDispatcher.RenderSection.CompileTask task) {
        if (!this.closed) {
            this.compileQueue.add(task);
            this.executor.execute(this::runTask);
        }
    }
 
    public void clearCompileQueue() {
        this.compileQueue.clear();
    }
 
    public boolean isQueueEmpty() {
        return this.compileQueue.size() == 0;
    }
 
    public void dispose() {
        this.closed = true;
        this.clearCompileQueue();
        this.copyLock.lock();
 
        try {
            for (SectionRenderDispatcher.SectionUberBuffers buffers : this.chunkUberBuffers.values()) {
                buffers.vertexBuffer.close();
                if (buffers.indexBuffer != null) {
                    buffers.indexBuffer.close();
                }
            }
        } finally {
            this.copyLock.unlock();
        }
    }
 
    @VisibleForDebug
    public String getStats() {
        return String.format(Locale.ROOT, "pC: %03d, aB: %02d", this.compileQueue.size(), this.bufferPool.getFreeBufferCount());
    }
 
    @VisibleForDebug
    public int getCompileQueueSize() {
        return this.compileQueue.size();
    }
 
    @VisibleForDebug
    public int getFreeBufferCount() {
        return this.bufferPool.getFreeBufferCount();
    }
 
    @OnlyIn(Dist.CLIENT)
    public class RenderSection {
        public static final int SIZE = 16;
        public final int index;
        public final AtomicReference<SectionMesh> sectionMesh;
        private SectionRenderDispatcher.RenderSection.@Nullable RebuildTask lastRebuildTask;
        private SectionRenderDispatcher.RenderSection.@Nullable ResortTransparencyTask lastResortTransparencyTask;
        private AABB bb;
        private boolean dirty;
        private volatile long sectionNode;
        private final BlockPos.MutableBlockPos renderOrigin;
        private boolean playerChanged;
        private long uploadedTime;
        private long fadeDuration;
        private boolean wasPreviouslyEmpty;
 
        public RenderSection(int index, long sectionNode) {
            Objects.requireNonNull(SectionRenderDispatcher.this);
            super();
            this.sectionMesh = new AtomicReference<>(CompiledSectionMesh.UNCOMPILED);
            this.dirty = true;
            this.sectionNode = SectionPos.asLong(-1, -1, -1);
            this.renderOrigin = new BlockPos.MutableBlockPos(-1, -1, -1);
            this.index = index;
            this.setSectionNode(sectionNode);
        }
 
        public float getVisibility(long now) {
            long elapsed = now - this.uploadedTime;
            return elapsed >= this.fadeDuration ? 1.0F : (float)elapsed / (float)this.fadeDuration;
        }
 
        public void setFadeDuration(long fadeDuration) {
            this.fadeDuration = fadeDuration;
        }
 
        public void setWasPreviouslyEmpty(boolean wasPreviouslyEmpty) {
            this.wasPreviouslyEmpty = wasPreviouslyEmpty;
        }
 
        public boolean wasPreviouslyEmpty() {
            return this.wasPreviouslyEmpty;
        }
 
        private boolean doesChunkExistAt(long sectionNode) {
            ChunkAccess chunk = SectionRenderDispatcher.this.level.getChunk(SectionPos.x(sectionNode), SectionPos.z(sectionNode), ChunkStatus.FULL, false);
            return chunk != null && SectionRenderDispatcher.this.level.getLightEngine().lightOnInColumn(SectionPos.getZeroNode(sectionNode));
        }
 
        public boolean hasAllNeighbors() {
            return this.doesChunkExistAt(SectionPos.offset(this.sectionNode, Direction.WEST))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, Direction.NORTH))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, Direction.EAST))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, Direction.SOUTH))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, -1, 0, -1))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, -1, 0, 1))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, 1, 0, -1))
                && this.doesChunkExistAt(SectionPos.offset(this.sectionNode, 1, 0, 1));
        }
 
        public AABB getBoundingBox() {
            return this.bb;
        }
 
        public void setSectionNode(long sectionNode) {
            this.reset();
            this.sectionNode = sectionNode;
            int x = SectionPos.sectionToBlockCoord(SectionPos.x(sectionNode));
            int y = SectionPos.sectionToBlockCoord(SectionPos.y(sectionNode));
            int z = SectionPos.sectionToBlockCoord(SectionPos.z(sectionNode));
            this.renderOrigin.set(x, y, z);
            this.bb = new AABB(x, y, z, x + 16, y + 16, z + 16);
        }
 
        public SectionMesh getSectionMesh() {
            return this.sectionMesh.get();
        }
 
        public void reset() {
            this.cancelTasks();
            SectionMesh mesh = this.sectionMesh.getAndSet(CompiledSectionMesh.UNCOMPILED);
            SectionRenderDispatcher.this.copyLock.lock();
 
            try {
                this.releaseSectionMesh(mesh);
            } finally {
                SectionRenderDispatcher.this.copyLock.unlock();
            }
 
            this.dirty = true;
            this.uploadedTime = 0L;
            this.wasPreviouslyEmpty = false;
        }
 
        public BlockPos getRenderOrigin() {
            return this.renderOrigin;
        }
 
        public long getSectionNode() {
            return this.sectionNode;
        }
 
        public void setDirty(boolean fromPlayer) {
            boolean wasDirty = this.dirty;
            this.dirty = true;
            this.playerChanged = fromPlayer | (wasDirty && this.playerChanged);
        }
 
        public void setNotDirty() {
            this.dirty = false;
            this.playerChanged = false;
        }
 
        public boolean isDirty() {
            return this.dirty;
        }
 
        public boolean isDirtyFromPlayer() {
            return this.dirty && this.playerChanged;
        }
 
        public long getNeighborSectionNode(Direction direction) {
            return SectionPos.offset(this.sectionNode, direction);
        }
 
        public void resortTransparency(SectionRenderDispatcher dispatcher) {
            if (this.getSectionMesh() instanceof CompiledSectionMesh mesh) {
                this.lastResortTransparencyTask = new SectionRenderDispatcher.RenderSection.ResortTransparencyTask(mesh);
                dispatcher.schedule(this.lastResortTransparencyTask);
            }
        }
 
        public boolean hasTranslucentGeometry() {
            return this.getSectionMesh().hasTranslucentGeometry();
        }
 
        public boolean transparencyResortingScheduled() {
            return this.lastResortTransparencyTask != null && !this.lastResortTransparencyTask.isCompleted.get();
        }
 
        protected void cancelTasks() {
            if (this.lastRebuildTask != null) {
                this.lastRebuildTask.cancel();
                this.lastRebuildTask = null;
            }
 
            if (this.lastResortTransparencyTask != null) {
                this.lastResortTransparencyTask.cancel();
                this.lastResortTransparencyTask = null;
            }
        }
 
        public SectionRenderDispatcher.RenderSection.CompileTask createCompileTask(RenderRegionCache cache) {
            this.cancelTasks();
            RenderSectionRegion region = cache.createRegion(SectionRenderDispatcher.this.level, this.sectionNode);
            boolean isRecompile = this.sectionMesh.get() != CompiledSectionMesh.UNCOMPILED;
            this.lastRebuildTask = new SectionRenderDispatcher.RenderSection.RebuildTask(region, isRecompile);
            return this.lastRebuildTask;
        }
 
        public void rebuildSectionAsync(RenderRegionCache cache) {
            SectionRenderDispatcher.RenderSection.CompileTask task = this.createCompileTask(cache);
            SectionRenderDispatcher.this.schedule(task);
        }
 
        public void compileSync(RenderRegionCache cache) {
            SectionRenderDispatcher.RenderSection.CompileTask task = this.createCompileTask(cache);
            task.doTask(SectionRenderDispatcher.this.fixedBuffers);
        }
 
        private SectionMesh setSectionMesh(SectionMesh sectionMesh) {
            SectionMesh oldMesh = this.sectionMesh.getAndSet(sectionMesh);
            SectionRenderDispatcher.this.renderer.addRecentlyCompiledSection(this);
            if (this.uploadedTime == 0L) {
                this.uploadedTime = Util.getMillis();
            }
 
            return oldMesh;
        }
 
        private void releaseSectionMesh(SectionMesh oldMesh) {
            oldMesh.close();
 
            for (SectionRenderDispatcher.SectionUberBuffers buffers : SectionRenderDispatcher.this.chunkUberBuffers.values()) {
                UberGpuBuffer<SectionMesh> vertexBuffer = buffers.vertexBuffer;
                vertexBuffer.removeAllocation(oldMesh);
                UberGpuBuffer<SectionMesh> indexBuffer = buffers.indexBuffer;
                if (indexBuffer != null) {
                    indexBuffer.removeAllocation(oldMesh);
                }
            }
        }
 
        private VertexSorting createVertexSorting(SectionPos sectionPos, Vec3 cameraPos) {
            return VertexSorting.byDistance(
                (float)(cameraPos.x - sectionPos.minBlockX()), (float)(cameraPos.y - sectionPos.minBlockY()), (float)(cameraPos.z - sectionPos.minBlockZ())
            );
        }
 
        private void checkSectionMesh(CompiledSectionMesh compiledSectionMesh) {
            boolean allBuffersUpdated = true;
 
            for (ChunkSectionLayer layer : ChunkSectionLayer.values()) {
                SectionMesh.SectionDraw draw = compiledSectionMesh.getSectionDraw(layer);
                if (draw != null) {
                    allBuffersUpdated &= compiledSectionMesh.isIndexBufferUploaded(layer);
                    allBuffersUpdated &= compiledSectionMesh.isVertexBufferUploaded(layer);
                }
            }
 
            if (allBuffersUpdated && this.sectionMesh.get() != compiledSectionMesh) {
                SectionMesh oldMesh = this.setSectionMesh(compiledSectionMesh);
                this.releaseSectionMesh(oldMesh);
            }
        }
 
        void vertexBufferUploadCallback(SectionMesh sectionMesh, ChunkSectionLayer layer) {
            if (sectionMesh instanceof CompiledSectionMesh compiledSectionMesh) {
                compiledSectionMesh.setVertexBufferUploaded(layer);
                this.checkSectionMesh(compiledSectionMesh);
            }
        }
 
        void indexBufferUploadCallback(SectionMesh sectionMesh, ChunkSectionLayer layer, boolean sortedIndexBuffer) {
            if (sectionMesh instanceof CompiledSectionMesh compiledSectionMesh) {
                compiledSectionMesh.setIndexBufferUploaded(layer);
                if (!sortedIndexBuffer) {
                    this.checkSectionMesh(compiledSectionMesh);
                }
            }
        }
 
        private boolean addSectionBuffersToUberBuffer(
            ChunkSectionLayer layer, CompiledSectionMesh key, @Nullable ByteBuffer vertexBuffer, @Nullable ByteBuffer indexBuffer
        ) {
            boolean success = true;
            SectionRenderDispatcher.this.copyLock.lock();
 
            try {
                SectionMesh.SectionDraw draw = key.getSectionDraw(layer);
                if (draw != null) {
                    SectionRenderDispatcher.SectionUberBuffers sectionBuffers = SectionRenderDispatcher.this.chunkUberBuffers.get(layer);
 
                    assert sectionBuffers != null;
 
                    if (vertexBuffer != null) {
                        UberGpuBuffer.UploadCallback<SectionMesh> callback = mesh -> this.vertexBufferUploadCallback(mesh, layer);
                        success &= sectionBuffers.vertexBuffer.addAllocation(key, callback, vertexBuffer);
                    }
 
                    if (indexBuffer != null) {
                        boolean sortedIndexBuffer = vertexBuffer == null;
                        UberGpuBuffer.UploadCallback<SectionMesh> callback = mesh -> this.indexBufferUploadCallback(mesh, layer, sortedIndexBuffer);
                        success &= sectionBuffers.indexBuffer.addAllocation(key, callback, indexBuffer);
                    } else {
                        key.setIndexBufferUploaded(layer);
                    }
                }
 
                if (!success && RenderSystem.isOnRenderThread()) {
                    SectionRenderDispatcher.this.uploadGlobalGeomBuffersToGPU();
                }
            } finally {
                SectionRenderDispatcher.this.copyLock.unlock();
            }
 
            return success;
        }
 
        @OnlyIn(Dist.CLIENT)
        public abstract class CompileTask {
            protected final AtomicBoolean isCancelled;
            protected final AtomicBoolean isCompleted;
            protected final boolean isRecompile;
 
            public CompileTask(boolean isRecompile) {
                Objects.requireNonNull(RenderSection.this);
                super();
                this.isCancelled = new AtomicBoolean(false);
                this.isCompleted = new AtomicBoolean(false);
                this.isRecompile = isRecompile;
            }
 
            public abstract SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult doTask(final SectionBufferBuilderPack buffers);
 
            public abstract void cancel();
 
            protected abstract String name();
 
            public boolean isRecompile() {
                return this.isRecompile;
            }
 
            public BlockPos getRenderOrigin() {
                return RenderSection.this.renderOrigin;
            }
 
            @OnlyIn(Dist.CLIENT)
            public static enum SectionTaskResult {
                SUCCESSFUL,
                CANCELLED;
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        private class RebuildTask extends SectionRenderDispatcher.RenderSection.CompileTask {
            protected final RenderSectionRegion region;
 
            public RebuildTask(RenderSectionRegion region, boolean isRecompile) {
                Objects.requireNonNull(RenderSection.this);
                super(isRecompile);
                this.region = region;
            }
 
            @Override
            protected String name() {
                return "rend_chk_rebuild";
            }
 
            @Override
            public SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult doTask(SectionBufferBuilderPack buffers) {
                if (this.isCancelled.get()) {
                    return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                } else {
                    long sectionNode = RenderSection.this.sectionNode;
                    SectionPos sectionPos = SectionPos.of(sectionNode);
                    if (this.isCancelled.get()) {
                        return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                    } else {
                        Vec3 cameraPos = SectionRenderDispatcher.this.cameraPosition.get();
 
                        SectionCompiler.Results results;
                        try (Zone ignored = Profiler.get().zone("Compile Section")) {
                            results = SectionRenderDispatcher.this.sectionCompiler
                                .compile(sectionPos, this.region, RenderSection.this.createVertexSorting(sectionPos, cameraPos), buffers);
                        }
 
                        TranslucencyPointOfView translucencyPointOfView = TranslucencyPointOfView.of(cameraPos, sectionNode);
                        CompiledSectionMesh compiledSectionMesh = new CompiledSectionMesh(translucencyPointOfView, results);
                        if (results.renderedLayers.isEmpty()) {
                            SectionMesh oldMesh = RenderSection.this.setSectionMesh(compiledSectionMesh);
                            SectionRenderDispatcher.this.copyLock.lock();
 
                            try {
                                RenderSection.this.releaseSectionMesh(oldMesh);
                            } finally {
                                SectionRenderDispatcher.this.copyLock.unlock();
                            }
 
                            return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.SUCCESSFUL;
                        } else {
                            for (Entry<ChunkSectionLayer, MeshData> entry : results.renderedLayers.entrySet()) {
                                MeshData meshData = entry.getValue();
                                boolean success = false;
 
                                while (!success) {
                                    if (this.isCancelled.get()) {
                                        results.release();
                                        SectionRenderDispatcher.this.copyLock.lock();
 
                                        try {
                                            RenderSection.this.releaseSectionMesh(compiledSectionMesh);
                                        } finally {
                                            SectionRenderDispatcher.this.copyLock.unlock();
                                        }
 
                                        return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                                    }
 
                                    success = RenderSection.this.addSectionBuffersToUberBuffer(
                                        entry.getKey(), compiledSectionMesh, meshData.vertexBuffer(), meshData.indexBuffer()
                                    );
                                    if (!success && !RenderSystem.isOnRenderThread()) {
                                        Thread.onSpinWait();
                                    }
                                }
 
                                meshData.close();
                            }
 
                            return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.SUCCESSFUL;
                        }
                    }
                }
            }
 
            @Override
            public void cancel() {
                if (this.isCancelled.compareAndSet(false, true)) {
                    RenderSection.this.setDirty(false);
                }
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        private class ResortTransparencyTask extends SectionRenderDispatcher.RenderSection.CompileTask {
            private final CompiledSectionMesh compiledSectionMesh;
 
            public ResortTransparencyTask(CompiledSectionMesh compiledSectionMesh) {
                Objects.requireNonNull(RenderSection.this);
                super(true);
                this.compiledSectionMesh = compiledSectionMesh;
            }
 
            @Override
            protected String name() {
                return "rend_chk_sort";
            }
 
            @Override
            public SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult doTask(SectionBufferBuilderPack buffers) {
                if (this.isCancelled.get()) {
                    return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                } else {
                    MeshData.SortState state = this.compiledSectionMesh.getTransparencyState();
                    if (state != null && !this.compiledSectionMesh.isEmpty(ChunkSectionLayer.TRANSLUCENT)) {
                        Vec3 cameraPos = SectionRenderDispatcher.this.cameraPosition.get();
                        long sectionNode = RenderSection.this.sectionNode;
                        VertexSorting vertexSorting = RenderSection.this.createVertexSorting(SectionPos.of(sectionNode), cameraPos);
                        TranslucencyPointOfView translucencyPointOfView = TranslucencyPointOfView.of(cameraPos, sectionNode);
                        if (!this.compiledSectionMesh.isDifferentPointOfView(translucencyPointOfView) && !translucencyPointOfView.isAxisAligned()) {
                            return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                        } else {
                            ByteBufferBuilder.Result indexBuffer = state.buildSortedIndexBuffer(buffers.buffer(ChunkSectionLayer.TRANSLUCENT), vertexSorting);
                            if (indexBuffer == null) {
                                return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                            } else {
                                boolean success = false;
 
                                while (!success) {
                                    if (this.isCancelled.get()) {
                                        indexBuffer.close();
                                        return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                                    }
 
                                    success = RenderSection.this.addSectionBuffersToUberBuffer(
                                        ChunkSectionLayer.TRANSLUCENT, this.compiledSectionMesh, null, indexBuffer.byteBuffer()
                                    );
                                    if (!success && !RenderSystem.isOnRenderThread()) {
                                        Thread.onSpinWait();
                                    }
                                }
 
                                indexBuffer.close();
                                this.compiledSectionMesh.setTranslucencyPointOfView(translucencyPointOfView);
                                return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.SUCCESSFUL;
                            }
                        }
                    } else {
                        return SectionRenderDispatcher.RenderSection.CompileTask.SectionTaskResult.CANCELLED;
                    }
                }
            }
 
            @Override
            public void cancel() {
                this.isCancelled.set(true);
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record RenderSectionBufferSlice(GpuBuffer vertexBuffer, long vertexBufferOffset, @Nullable GpuBuffer indexBuffer, long indexBufferOffset) {
    }
 
    @OnlyIn(Dist.CLIENT)
    private record SectionUberBuffers(UberGpuBuffer<SectionMesh> vertexBuffer, @Nullable UberGpuBuffer<SectionMesh> indexBuffer) {
    }
}

引用的其他类

  • GraphicsWorkarounds

    • 引用位置: 方法调用
    • 关联成员: GraphicsWorkarounds.get()
  • RenderSystem

    • 引用位置: 方法调用
    • 关联成员: RenderSystem.getDevice(), RenderSystem.isOnRenderThread()
  • VertexSorting

    • 引用位置: 方法调用
    • 关联成员: VertexSorting.byDistance()
  • CrashReport

    • 引用位置: 方法调用
    • 关联成员: CrashReport.forThrowable()
  • TracingExecutor

    • 引用位置: 参数/字段
  • Minecraft

    • 引用位置: 方法调用
    • 关联成员: Minecraft.getInstance()
  • ClientLevel

    • 引用位置: 参数/字段
  • LevelRenderer

    • 引用位置: 参数/字段
  • RenderBuffers

    • 引用位置: 参数
  • SectionBufferBuilderPack

    • 引用位置: 字段
  • SectionBufferBuilderPool

    • 引用位置: 字段
  • ChunkSectionLayer

    • 引用位置: 参数/字段/方法调用
    • 关联成员: ChunkSectionLayer.values()
  • CompileTaskDynamicQueue

    • 引用位置: 字段/构造调用
    • 关联成员: CompileTaskDynamicQueue()
  • CompiledSectionMesh

    • 引用位置: 构造调用
    • 关联成员: CompiledSectionMesh()
  • RenderRegionCache

    • 引用位置: 参数
  • SectionCompiler

    • 引用位置: 参数/字段
  • SectionMesh

    • 引用位置: 参数
  • TranslucencyPointOfView

    • 引用位置: 方法调用
    • 关联成员: TranslucencyPointOfView.of()
  • BlockPos

    • 引用位置: 方法调用/构造调用
    • 关联成员: BlockPos.MutableBlockPos(), MutableBlockPos()
  • SectionPos

    • 引用位置: 方法调用
    • 关联成员: SectionPos.asLong(), SectionPos.getZeroNode(), SectionPos.of(), SectionPos.offset(), SectionPos.sectionToBlockCoord(), SectionPos.x(), SectionPos.y(), SectionPos.z()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getMillis(), Util.makeEnumMap()
  • Profiler

    • 引用位置: 方法调用
    • 关联成员: Profiler.get()
  • AABB

    • 引用位置: 构造调用
    • 关联成员: AABB()
  • Vec3

    • 引用位置: 参数/字段