minecraft-src/com/mojang/blaze3d/TracyFrameCapture.java
2025-07-04 03:45:38 +03:00

131 lines
4.3 KiB
Java

package com.mojang.blaze3d;
import com.mojang.blaze3d.buffers.BufferType;
import com.mojang.blaze3d.buffers.BufferUsage;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
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;
import org.jetbrains.annotations.Nullable;
@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;
@Nullable
private GpuTexture frameBuffer;
@Nullable
private GpuBuffer pixelbuffer;
private int lastCaptureDelay;
private boolean capturedThisFrame;
private TracyFrameCapture.Status status = TracyFrameCapture.Status.WAITING_FOR_CAPTURE;
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;
if (this.frameBuffer != null) {
this.frameBuffer.close();
}
this.frameBuffer = RenderSystem.getDevice().createTexture("Tracy Frame Capture", TextureFormat.RGBA8, width, height, 1);
if (this.pixelbuffer != null) {
this.pixelbuffer.close();
}
this.pixelbuffer = RenderSystem.getDevice()
.createBuffer(() -> "Tracy Frame Capture buffer", BufferType.PIXEL_PACK, BufferUsage.STREAM_READ, width * height * 4);
}
}
public void capture(RenderTarget renderTarget) {
if (this.status == TracyFrameCapture.Status.WAITING_FOR_CAPTURE
&& !this.capturedThisFrame
&& renderTarget.getColorTexture() != null
&& this.pixelbuffer != null
&& this.frameBuffer != 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(this.frameBuffer, OptionalInt.empty())) {
renderPass.setPipeline(RenderPipelines.TRACY_BLIT);
renderPass.setVertexBuffer(0, RenderSystem.getQuadVertexBuffer());
renderPass.setIndexBuffer(gpuBuffer, autoStorageIndexBuffer.type());
renderPass.bindSampler("InSampler", renderTarget.getColorTexture());
renderPass.drawIndexed(0, 6);
}
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.pixelbuffer != null) {
this.status = TracyFrameCapture.Status.WAITING_FOR_CAPTURE;
try (GpuBuffer.ReadView readView = RenderSystem.getDevice().createCommandEncoder().readBuffer(this.pixelbuffer)) {
TracyClient.frameImage(readView.data(), this.width, this.height, this.lastCaptureDelay, true);
}
}
}
public void endFrame() {
this.lastCaptureDelay++;
this.capturedThisFrame = false;
TracyClient.markFrame();
}
public void close() {
if (this.frameBuffer != null) {
this.frameBuffer.close();
}
if (this.pixelbuffer != null) {
this.pixelbuffer.close();
}
}
@Environment(EnvType.CLIENT)
static enum Status {
WAITING_FOR_CAPTURE,
WAITING_FOR_COPY,
WAITING_FOR_UPLOAD;
}
}