131 lines
4.3 KiB
Java
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;
|
|
}
|
|
}
|