minecraft-src/com/mojang/blaze3d/TracyFrameCapture.java
2025-09-18 12:27:44 +00:00

126 lines
4.7 KiB
Java

package com.mojang.blaze3d;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
import com.mojang.blaze3d.textures.GpuTextureView;
import com.mojang.blaze3d.textures.TextureFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.jtracy.TracyClient;
import java.util.OptionalInt;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.RenderPipelines;
@Environment(EnvType.CLIENT)
public class TracyFrameCapture implements AutoCloseable {
private static final int MAX_WIDTH = 320;
private static final int MAX_HEIGHT = 180;
private static final int BYTES_PER_PIXEL = 4;
private int targetWidth;
private int targetHeight;
private int width;
private int height;
private GpuTexture frameBuffer;
private GpuTextureView frameBufferView;
private GpuBuffer pixelbuffer;
private int lastCaptureDelay;
private boolean capturedThisFrame;
private TracyFrameCapture.Status status = TracyFrameCapture.Status.WAITING_FOR_CAPTURE;
public TracyFrameCapture() {
this.width = 320;
this.height = 180;
GpuDevice gpuDevice = RenderSystem.getDevice();
this.frameBuffer = gpuDevice.createTexture("Tracy Frame Capture", 10, TextureFormat.RGBA8, this.width, this.height, 1, 1);
this.frameBufferView = gpuDevice.createTextureView(this.frameBuffer);
this.pixelbuffer = gpuDevice.createBuffer(() -> "Tracy Frame Capture buffer", 9, this.width * this.height * 4);
}
private void resize(int width, int height) {
float f = (float)width / height;
if (width > 320) {
width = 320;
height = (int)(320.0F / f);
}
if (height > 180) {
width = (int)(180.0F * f);
height = 180;
}
width = width / 4 * 4;
height = height / 4 * 4;
if (this.width != width || this.height != height) {
this.width = width;
this.height = height;
GpuDevice gpuDevice = RenderSystem.getDevice();
this.frameBuffer.close();
this.frameBuffer = gpuDevice.createTexture("Tracy Frame Capture", 10, TextureFormat.RGBA8, width, height, 1, 1);
this.frameBufferView.close();
this.frameBufferView = gpuDevice.createTextureView(this.frameBuffer);
this.pixelbuffer.close();
this.pixelbuffer = gpuDevice.createBuffer(() -> "Tracy Frame Capture buffer", 9, width * height * 4);
}
}
public void capture(RenderTarget renderTarget) {
if (this.status == TracyFrameCapture.Status.WAITING_FOR_CAPTURE && !this.capturedThisFrame && renderTarget.getColorTexture() != null) {
this.capturedThisFrame = true;
if (renderTarget.width != this.targetWidth || renderTarget.height != this.targetHeight) {
this.targetWidth = renderTarget.width;
this.targetHeight = renderTarget.height;
this.resize(this.targetWidth, this.targetHeight);
}
this.status = TracyFrameCapture.Status.WAITING_FOR_COPY;
CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder();
RenderSystem.AutoStorageIndexBuffer autoStorageIndexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
GpuBuffer gpuBuffer = autoStorageIndexBuffer.getBuffer(6);
try (RenderPass renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Tracy blit", this.frameBufferView, OptionalInt.empty())) {
renderPass.setPipeline(RenderPipelines.TRACY_BLIT);
renderPass.setVertexBuffer(0, RenderSystem.getQuadVertexBuffer());
renderPass.setIndexBuffer(gpuBuffer, autoStorageIndexBuffer.type());
renderPass.bindSampler("InSampler", renderTarget.getColorTextureView());
renderPass.drawIndexed(0, 0, 6, 1);
}
commandEncoder.copyTextureToBuffer(this.frameBuffer, this.pixelbuffer, 0, () -> this.status = TracyFrameCapture.Status.WAITING_FOR_UPLOAD, 0);
this.lastCaptureDelay = 0;
}
}
public void upload() {
if (this.status == TracyFrameCapture.Status.WAITING_FOR_UPLOAD) {
this.status = TracyFrameCapture.Status.WAITING_FOR_CAPTURE;
try (GpuBuffer.MappedView mappedView = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.pixelbuffer, true, false)) {
TracyClient.frameImage(mappedView.data(), this.width, this.height, this.lastCaptureDelay, true);
}
}
}
public void endFrame() {
this.lastCaptureDelay++;
this.capturedThisFrame = false;
TracyClient.markFrame();
}
public void close() {
this.frameBuffer.close();
this.frameBufferView.close();
this.pixelbuffer.close();
}
@Environment(EnvType.CLIENT)
static enum Status {
WAITING_FOR_CAPTURE,
WAITING_FOR_COPY,
WAITING_FOR_UPLOAD;
}
}