712 lines
28 KiB
Java
712 lines
28 KiB
Java
package com.mojang.blaze3d.opengl;
|
|
|
|
import com.mojang.blaze3d.buffers.BufferType;
|
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
|
import com.mojang.blaze3d.platform.NativeImage;
|
|
import com.mojang.blaze3d.platform.Window;
|
|
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.vertex.VertexFormat;
|
|
import com.mojang.logging.LogUtils;
|
|
import it.unimi.dsi.fastutil.ints.IntList;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.IntBuffer;
|
|
import java.util.Collection;
|
|
import java.util.OptionalDouble;
|
|
import java.util.OptionalInt;
|
|
import java.util.function.Consumer;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.util.ARGB;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.lwjgl.opengl.GL11;
|
|
import org.slf4j.Logger;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class GlCommandEncoder implements CommandEncoder {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private final GlDevice device;
|
|
private final int readFbo;
|
|
private final int drawFbo;
|
|
@Nullable
|
|
private RenderPipeline lastPipeline;
|
|
private boolean inRenderPass;
|
|
@Nullable
|
|
private GlProgram lastProgram;
|
|
|
|
protected GlCommandEncoder(GlDevice device) {
|
|
this.device = device;
|
|
this.readFbo = device.directStateAccess().createFrameBufferObject();
|
|
this.drawFbo = device.directStateAccess().createFrameBufferObject();
|
|
}
|
|
|
|
@Override
|
|
public RenderPass createRenderPass(GpuTexture gpuTexture, OptionalInt optionalInt) {
|
|
return this.createRenderPass(gpuTexture, optionalInt, null, OptionalDouble.empty());
|
|
}
|
|
|
|
@Override
|
|
public RenderPass createRenderPass(GpuTexture gpuTexture, OptionalInt optionalInt, @Nullable GpuTexture gpuTexture2, OptionalDouble optionalDouble) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before creating a new one!");
|
|
} else {
|
|
if (optionalDouble.isPresent() && gpuTexture2 == null) {
|
|
LOGGER.warn("Depth clear value was provided but no depth texture is being used");
|
|
}
|
|
|
|
if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Color texture is closed");
|
|
} else if (gpuTexture2 != null && gpuTexture2.isClosed()) {
|
|
throw new IllegalStateException("Depth texture is closed");
|
|
} else {
|
|
this.inRenderPass = true;
|
|
int i = ((GlTexture)gpuTexture).getFbo(this.device.directStateAccess(), gpuTexture2);
|
|
GlStateManager._glBindFramebuffer(36160, i);
|
|
int j = 0;
|
|
if (optionalInt.isPresent()) {
|
|
int k = optionalInt.getAsInt();
|
|
GL11.glClearColor(ARGB.redFloat(k), ARGB.greenFloat(k), ARGB.blueFloat(k), ARGB.alphaFloat(k));
|
|
j |= 16384;
|
|
}
|
|
|
|
if (gpuTexture2 != null && optionalDouble.isPresent()) {
|
|
GL11.glClearDepth(optionalDouble.getAsDouble());
|
|
j |= 256;
|
|
}
|
|
|
|
if (j != 0) {
|
|
GlStateManager._disableScissorTest();
|
|
GlStateManager._depthMask(true);
|
|
GlStateManager._colorMask(true, true, true, true);
|
|
GlStateManager._clear(j);
|
|
}
|
|
|
|
GlStateManager._viewport(0, 0, gpuTexture.getWidth(0), gpuTexture.getHeight(0));
|
|
this.lastPipeline = null;
|
|
return new GlRenderPass(this, gpuTexture2 != null);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearColorTexture(GpuTexture gpuTexture, int i) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before creating a new one!");
|
|
} else if (!gpuTexture.getFormat().hasColorAspect()) {
|
|
throw new IllegalStateException("Trying to clear a non-color texture as color");
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Color texture is closed");
|
|
} else {
|
|
this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, ((GlTexture)gpuTexture).id, 0, 0, 36160);
|
|
GL11.glClearColor(ARGB.redFloat(i), ARGB.greenFloat(i), ARGB.blueFloat(i), ARGB.alphaFloat(i));
|
|
GlStateManager._disableScissorTest();
|
|
GlStateManager._colorMask(true, true, true, true);
|
|
GlStateManager._clear(16384);
|
|
GlStateManager._glFramebufferTexture2D(36160, 36064, 3553, 0, 0);
|
|
GlStateManager._glBindFramebuffer(36160, 0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearColorAndDepthTextures(GpuTexture gpuTexture, int i, GpuTexture gpuTexture2, double d) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before creating a new one!");
|
|
} else if (!gpuTexture.getFormat().hasColorAspect()) {
|
|
throw new IllegalStateException("Trying to clear a non-color texture as color");
|
|
} else if (!gpuTexture2.getFormat().hasDepthAspect()) {
|
|
throw new IllegalStateException("Trying to clear a non-depth texture as depth");
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Color texture is closed");
|
|
} else if (gpuTexture2.isClosed()) {
|
|
throw new IllegalStateException("Depth texture is closed");
|
|
} else {
|
|
int j = ((GlTexture)gpuTexture).getFbo(this.device.directStateAccess(), gpuTexture2);
|
|
GlStateManager._glBindFramebuffer(36160, j);
|
|
GlStateManager._disableScissorTest();
|
|
GL11.glClearDepth(d);
|
|
GL11.glClearColor(ARGB.redFloat(i), ARGB.greenFloat(i), ARGB.blueFloat(i), ARGB.alphaFloat(i));
|
|
GlStateManager._depthMask(true);
|
|
GlStateManager._colorMask(true, true, true, true);
|
|
GlStateManager._clear(16640);
|
|
GlStateManager._glBindFramebuffer(36160, 0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearDepthTexture(GpuTexture gpuTexture, double d) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before creating a new one!");
|
|
} else if (!gpuTexture.getFormat().hasDepthAspect()) {
|
|
throw new IllegalStateException("Trying to clear a non-depth texture as depth");
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Depth texture is closed");
|
|
} else {
|
|
this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, 0, ((GlTexture)gpuTexture).id, 0, 36160);
|
|
GL11.glDrawBuffer(0);
|
|
GL11.glClearDepth(d);
|
|
GlStateManager._depthMask(true);
|
|
GlStateManager._disableScissorTest();
|
|
GlStateManager._clear(256);
|
|
GL11.glDrawBuffer(36064);
|
|
GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, 0, 0);
|
|
GlStateManager._glBindFramebuffer(36160, 0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void writeToBuffer(GpuBuffer gpuBuffer, ByteBuffer byteBuffer, int i) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else {
|
|
GlBuffer glBuffer = (GlBuffer)gpuBuffer;
|
|
if (glBuffer.closed) {
|
|
throw new IllegalStateException("Buffer already closed");
|
|
} else if (!glBuffer.usage().isWritable()) {
|
|
throw new IllegalStateException("Buffer is not writable");
|
|
} else {
|
|
int j = byteBuffer.remaining();
|
|
if (j + i > glBuffer.size) {
|
|
throw new IllegalArgumentException(
|
|
"Cannot write more data than this buffer can hold (attempting to write " + j + " bytes at offset " + i + " to " + glBuffer.size + " size buffer)"
|
|
);
|
|
} else {
|
|
GlStateManager._glBindBuffer(GlConst.toGl(glBuffer.type()), glBuffer.handle);
|
|
if (glBuffer.initialized) {
|
|
GlStateManager._glBufferSubData(GlConst.toGl(glBuffer.type()), i, byteBuffer);
|
|
} else if (i == 0 && j == glBuffer.size) {
|
|
GlStateManager._glBufferData(GlConst.toGl(glBuffer.type()), byteBuffer, GlConst.toGl(glBuffer.usage()));
|
|
GlBuffer.MEMORY_POOl.malloc(glBuffer.handle, glBuffer.size);
|
|
glBuffer.initialized = true;
|
|
this.device.debugLabels().applyLabel(glBuffer);
|
|
} else {
|
|
GlStateManager._glBufferData(GlConst.toGl(glBuffer.type()), glBuffer.size, GlConst.toGl(glBuffer.usage()));
|
|
GlStateManager._glBufferSubData(GlConst.toGl(glBuffer.type()), i, byteBuffer);
|
|
GlBuffer.MEMORY_POOl.malloc(glBuffer.handle, glBuffer.size);
|
|
glBuffer.initialized = true;
|
|
this.device.debugLabels().applyLabel(glBuffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public GpuBuffer.ReadView readBuffer(GpuBuffer gpuBuffer) {
|
|
return this.readBuffer(gpuBuffer, 0, gpuBuffer.size());
|
|
}
|
|
|
|
@Override
|
|
public GpuBuffer.ReadView readBuffer(GpuBuffer gpuBuffer, int i, int j) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else {
|
|
GlBuffer glBuffer = (GlBuffer)gpuBuffer;
|
|
if (glBuffer.closed) {
|
|
throw new IllegalStateException("Buffer already closed");
|
|
} else if (!glBuffer.usage().isReadable()) {
|
|
throw new IllegalStateException("Buffer is not readable");
|
|
} else if (i + j > glBuffer.size) {
|
|
throw new IllegalArgumentException(
|
|
"Cannot read more data than this buffer can hold (attempting to read " + j + " bytes at offset " + i + " from " + glBuffer.size + " size buffer)"
|
|
);
|
|
} else {
|
|
GlStateManager.clearGlErrors();
|
|
GlStateManager._glBindBuffer(GlConst.toGl(glBuffer.type()), glBuffer.handle);
|
|
ByteBuffer byteBuffer = GlStateManager._glMapBufferRange(GlConst.toGl(glBuffer.type()), i, j, 1);
|
|
if (byteBuffer == null) {
|
|
throw new IllegalStateException("Can't read buffer, opengl error " + GlStateManager._getError());
|
|
} else {
|
|
return new GlBuffer.ReadView(GlConst.toGl(glBuffer.type()), byteBuffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void writeToTexture(GpuTexture gpuTexture, NativeImage nativeImage) {
|
|
int i = gpuTexture.getWidth(0);
|
|
int j = gpuTexture.getHeight(0);
|
|
if (nativeImage.getWidth() != i || nativeImage.getHeight() != j) {
|
|
throw new IllegalArgumentException(
|
|
"Cannot replace texture of size " + i + "x" + j + " with image of size " + nativeImage.getWidth() + "x" + nativeImage.getHeight()
|
|
);
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Destination texture is closed");
|
|
} else {
|
|
this.writeToTexture(gpuTexture, nativeImage, 0, 0, 0, i, j, 0, 0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void writeToTexture(GpuTexture gpuTexture, NativeImage nativeImage, int i, int j, int k, int l, int m, int n, int o) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else if (i >= 0 && i < gpuTexture.getMipLevels()) {
|
|
if (n + l > nativeImage.getWidth() || o + m > nativeImage.getHeight()) {
|
|
throw new IllegalArgumentException(
|
|
"Copy source ("
|
|
+ nativeImage.getWidth()
|
|
+ "x"
|
|
+ nativeImage.getHeight()
|
|
+ ") is not large enough to read a rectangle of "
|
|
+ l
|
|
+ "x"
|
|
+ m
|
|
+ " from "
|
|
+ n
|
|
+ "x"
|
|
+ o
|
|
);
|
|
} else if (j + l > gpuTexture.getWidth(i) || k + m > gpuTexture.getHeight(i)) {
|
|
throw new IllegalArgumentException(
|
|
"Dest texture (" + l + "x" + m + ") is not large enough to write a rectangle of " + l + "x" + m + " at " + j + "x" + k + " (at mip level " + i + ")"
|
|
);
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Destination texture is closed");
|
|
} else {
|
|
GlStateManager._bindTexture(((GlTexture)gpuTexture).id);
|
|
GlStateManager._pixelStore(3314, nativeImage.getWidth());
|
|
GlStateManager._pixelStore(3316, n);
|
|
GlStateManager._pixelStore(3315, o);
|
|
GlStateManager._pixelStore(3317, nativeImage.format().components());
|
|
GlStateManager._texSubImage2D(3553, i, j, k, l, m, GlConst.toGl(nativeImage.format()), 5121, nativeImage.getPointer());
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Invalid mipLevel " + i + ", must be >= 0 and < " + gpuTexture.getMipLevels());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void writeToTexture(GpuTexture gpuTexture, IntBuffer intBuffer, NativeImage.Format format, int i, int j, int k, int l, int m) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else if (i >= 0 && i < gpuTexture.getMipLevels()) {
|
|
if (l * m > intBuffer.remaining()) {
|
|
throw new IllegalArgumentException(
|
|
"Copy would overrun the source buffer (remaining length of " + intBuffer.remaining() + ", but copy is " + l + "x" + m + ")"
|
|
);
|
|
} else if (j + l > gpuTexture.getWidth(i) || k + m > gpuTexture.getHeight(i)) {
|
|
throw new IllegalArgumentException(
|
|
"Dest texture ("
|
|
+ gpuTexture.getWidth(i)
|
|
+ "x"
|
|
+ gpuTexture.getHeight(i)
|
|
+ ") is not large enough to write a rectangle of "
|
|
+ l
|
|
+ "x"
|
|
+ m
|
|
+ " at "
|
|
+ j
|
|
+ "x"
|
|
+ k
|
|
);
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Destination texture is closed");
|
|
} else {
|
|
GlStateManager._bindTexture(((GlTexture)gpuTexture).id);
|
|
GlStateManager._pixelStore(3314, l);
|
|
GlStateManager._pixelStore(3316, 0);
|
|
GlStateManager._pixelStore(3315, 0);
|
|
GlStateManager._pixelStore(3317, format.components());
|
|
GlStateManager._texSubImage2D(3553, i, j, k, l, m, GlConst.toGl(format), 5121, intBuffer);
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Invalid mipLevel, must be >= 0 and < " + gpuTexture.getMipLevels());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void copyTextureToBuffer(GpuTexture gpuTexture, GpuBuffer gpuBuffer, int i, Runnable runnable, int j) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else {
|
|
this.copyTextureToBuffer(gpuTexture, gpuBuffer, i, runnable, j, 0, 0, gpuTexture.getWidth(j), gpuTexture.getHeight(j));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void copyTextureToBuffer(GpuTexture gpuTexture, GpuBuffer gpuBuffer, int i, Runnable runnable, int j, int k, int l, int m, int n) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else if (j >= 0 && j < gpuTexture.getMipLevels()) {
|
|
if (gpuTexture.getWidth(j) * gpuTexture.getHeight(j) * gpuTexture.getFormat().pixelSize() + i > gpuBuffer.size()) {
|
|
throw new IllegalArgumentException(
|
|
"Buffer of size "
|
|
+ gpuBuffer.size()
|
|
+ " is not large enough to hold "
|
|
+ m
|
|
+ "x"
|
|
+ n
|
|
+ " pixels ("
|
|
+ gpuTexture.getFormat().pixelSize()
|
|
+ " bytes each) starting from offset "
|
|
+ i
|
|
);
|
|
} else if (gpuBuffer.type() != BufferType.PIXEL_PACK) {
|
|
throw new IllegalArgumentException("Buffer of type " + gpuBuffer.type() + " cannot be used to retrieve a texture");
|
|
} else if (k + m > gpuTexture.getWidth(j) || l + n > gpuTexture.getHeight(j)) {
|
|
throw new IllegalArgumentException(
|
|
"Copy source texture ("
|
|
+ gpuTexture.getWidth(j)
|
|
+ "x"
|
|
+ gpuTexture.getHeight(j)
|
|
+ ") is not large enough to read a rectangle of "
|
|
+ m
|
|
+ "x"
|
|
+ n
|
|
+ " from "
|
|
+ k
|
|
+ ","
|
|
+ l
|
|
);
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Source texture is closed");
|
|
} else if (gpuBuffer.isClosed()) {
|
|
throw new IllegalStateException("Destination buffer is closed");
|
|
} else {
|
|
GlStateManager.clearGlErrors();
|
|
this.device.directStateAccess().bindFrameBufferTextures(this.readFbo, ((GlTexture)gpuTexture).glId(), 0, j, 36008);
|
|
GlStateManager._glBindBuffer(GlConst.toGl(gpuBuffer.type()), ((GlBuffer)gpuBuffer).handle);
|
|
GlStateManager._pixelStore(3330, m);
|
|
GlStateManager._readPixels(k, l, m, n, GlConst.toGlExternalId(gpuTexture.getFormat()), GlConst.toGlType(gpuTexture.getFormat()), i);
|
|
RenderSystem.queueFencedTask(runnable);
|
|
GlStateManager._glFramebufferTexture2D(36008, 36064, 3553, 0, j);
|
|
GlStateManager._glBindFramebuffer(36008, 0);
|
|
GlStateManager._glBindBuffer(GlConst.toGl(gpuBuffer.type()), 0);
|
|
int o = GlStateManager._getError();
|
|
if (o != 0) {
|
|
throw new IllegalStateException("Couldn't perform copyTobuffer for texture " + gpuTexture.getLabel() + ": GL error " + o);
|
|
}
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Invalid mipLevel " + j + ", must be >= 0 and < " + gpuTexture.getMipLevels());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void copyTextureToTexture(GpuTexture gpuTexture, GpuTexture gpuTexture2, int i, int j, int k, int l, int m, int n, int o) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else if (i >= 0 && i < gpuTexture.getMipLevels() && i < gpuTexture2.getMipLevels()) {
|
|
if (j + n > gpuTexture2.getWidth(i) || k + o > gpuTexture2.getHeight(i)) {
|
|
throw new IllegalArgumentException(
|
|
"Dest texture ("
|
|
+ gpuTexture2.getWidth(i)
|
|
+ "x"
|
|
+ gpuTexture2.getHeight(i)
|
|
+ ") is not large enough to write a rectangle of "
|
|
+ n
|
|
+ "x"
|
|
+ o
|
|
+ " at "
|
|
+ j
|
|
+ "x"
|
|
+ k
|
|
);
|
|
} else if (l + n > gpuTexture.getWidth(i) || m + o > gpuTexture.getHeight(i)) {
|
|
throw new IllegalArgumentException(
|
|
"Source texture ("
|
|
+ gpuTexture.getWidth(i)
|
|
+ "x"
|
|
+ gpuTexture.getHeight(i)
|
|
+ ") is not large enough to read a rectangle of "
|
|
+ n
|
|
+ "x"
|
|
+ o
|
|
+ " at "
|
|
+ l
|
|
+ "x"
|
|
+ m
|
|
);
|
|
} else if (gpuTexture.isClosed()) {
|
|
throw new IllegalStateException("Source texture is closed");
|
|
} else if (gpuTexture2.isClosed()) {
|
|
throw new IllegalStateException("Destination texture is closed");
|
|
} else {
|
|
GlStateManager.clearGlErrors();
|
|
GlStateManager._disableScissorTest();
|
|
boolean bl = gpuTexture.getFormat().hasDepthAspect();
|
|
int p = ((GlTexture)gpuTexture).glId();
|
|
int q = ((GlTexture)gpuTexture2).glId();
|
|
this.device.directStateAccess().bindFrameBufferTextures(this.readFbo, bl ? 0 : p, bl ? p : 0, 0, 0);
|
|
this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, bl ? 0 : q, bl ? q : 0, 0, 0);
|
|
this.device.directStateAccess().blitFrameBuffers(this.readFbo, this.drawFbo, l, m, n, o, j, k, n, o, bl ? 256 : 16384, 9728);
|
|
int r = GlStateManager._getError();
|
|
if (r != 0) {
|
|
throw new IllegalStateException(
|
|
"Couldn't perform copyToTexture for texture " + gpuTexture.getLabel() + " to " + gpuTexture2.getLabel() + ": GL error " + r
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Invalid mipLevel " + i + ", must be >= 0 and < " + gpuTexture.getMipLevels() + " and < " + gpuTexture2.getMipLevels());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void presentTexture(GpuTexture gpuTexture) {
|
|
if (this.inRenderPass) {
|
|
throw new IllegalStateException("Close the existing render pass before performing additional commands");
|
|
} else if (!gpuTexture.getFormat().hasColorAspect()) {
|
|
throw new IllegalStateException("Cannot present a non-color texture!");
|
|
} else {
|
|
GlStateManager._disableScissorTest();
|
|
GlStateManager._viewport(0, 0, gpuTexture.getWidth(0), gpuTexture.getHeight(0));
|
|
GlStateManager._depthMask(true);
|
|
GlStateManager._colorMask(true, true, true, true);
|
|
this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, ((GlTexture)gpuTexture).glId(), 0, 0, 0);
|
|
this.device
|
|
.directStateAccess()
|
|
.blitFrameBuffers(
|
|
this.drawFbo, 0, 0, 0, gpuTexture.getWidth(0), gpuTexture.getHeight(0), 0, 0, gpuTexture.getWidth(0), gpuTexture.getHeight(0), 16384, 9728
|
|
);
|
|
}
|
|
}
|
|
|
|
protected void executeDrawMultiple(
|
|
GlRenderPass renderPass, Collection<RenderPass.Draw> draws, @Nullable GpuBuffer buffer, @Nullable VertexFormat.IndexType indexType
|
|
) {
|
|
if (this.trySetup(renderPass)) {
|
|
if (indexType == null) {
|
|
indexType = VertexFormat.IndexType.SHORT;
|
|
}
|
|
|
|
for (RenderPass.Draw draw : draws) {
|
|
VertexFormat.IndexType indexType2 = draw.indexType() == null ? indexType : draw.indexType();
|
|
renderPass.setIndexBuffer(draw.indexBuffer() == null ? buffer : draw.indexBuffer(), indexType2);
|
|
renderPass.setVertexBuffer(draw.slot(), draw.vertexBuffer());
|
|
if (GlRenderPass.VALIDATION) {
|
|
if (renderPass.indexBuffer == null) {
|
|
throw new IllegalStateException("Missing index buffer");
|
|
}
|
|
|
|
if (renderPass.indexBuffer.isClosed()) {
|
|
throw new IllegalStateException("Index buffer has been closed!");
|
|
}
|
|
|
|
if (renderPass.vertexBuffers[0] == null) {
|
|
throw new IllegalStateException("Missing vertex buffer at slot 0");
|
|
}
|
|
|
|
if (renderPass.vertexBuffers[0].isClosed()) {
|
|
throw new IllegalStateException("Vertex buffer at slot 0 has been closed!");
|
|
}
|
|
}
|
|
|
|
Consumer<RenderPass.UniformUploader> consumer = draw.uniformUploaderConsumer();
|
|
if (consumer != null) {
|
|
consumer.accept((RenderPass.UniformUploader)(string, fs) -> {
|
|
Uniform uniform = renderPass.pipeline.program().getUniform(string);
|
|
if (uniform != null) {
|
|
uniform.set(fs);
|
|
uniform.upload();
|
|
}
|
|
});
|
|
}
|
|
|
|
this.drawFromBuffers(renderPass, draw.firstIndex(), draw.indexCount(), indexType2, renderPass.pipeline);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void executeDraw(GlRenderPass renderPass, int firstIndex, int indexCount, @Nullable VertexFormat.IndexType indexType) {
|
|
if (this.trySetup(renderPass)) {
|
|
if (GlRenderPass.VALIDATION) {
|
|
if (indexType != null) {
|
|
if (renderPass.indexBuffer == null) {
|
|
throw new IllegalStateException("Missing index buffer");
|
|
}
|
|
|
|
if (renderPass.indexBuffer.isClosed()) {
|
|
throw new IllegalStateException("Index buffer has been closed!");
|
|
}
|
|
}
|
|
|
|
if (renderPass.vertexBuffers[0] == null) {
|
|
throw new IllegalStateException("Missing vertex buffer at slot 0");
|
|
}
|
|
|
|
if (renderPass.vertexBuffers[0].isClosed()) {
|
|
throw new IllegalStateException("Vertex buffer at slot 0 has been closed!");
|
|
}
|
|
}
|
|
|
|
this.drawFromBuffers(renderPass, firstIndex, indexCount, indexType, renderPass.pipeline);
|
|
}
|
|
}
|
|
|
|
private void drawFromBuffers(GlRenderPass renderPass, int firstIndex, int indexCount, @Nullable VertexFormat.IndexType indexType, GlRenderPipeline pipeline) {
|
|
this.device.vertexArrayCache().bindVertexArray(pipeline.info().getVertexFormat(), (GlBuffer)renderPass.vertexBuffers[0]);
|
|
if (indexType != null) {
|
|
GlStateManager._glBindBuffer(34963, ((GlBuffer)renderPass.indexBuffer).handle);
|
|
GlStateManager._drawElements(GlConst.toGl(pipeline.info().getVertexFormatMode()), indexCount, GlConst.toGl(indexType), (long)firstIndex * indexType.bytes);
|
|
} else {
|
|
GlStateManager._drawArrays(GlConst.toGl(pipeline.info().getVertexFormatMode()), firstIndex, indexCount);
|
|
}
|
|
}
|
|
|
|
private boolean trySetup(GlRenderPass renderPass) {
|
|
if (GlRenderPass.VALIDATION) {
|
|
if (renderPass.pipeline == null) {
|
|
throw new IllegalStateException("Can't draw without a render pipeline");
|
|
}
|
|
|
|
if (renderPass.pipeline.program() == GlProgram.INVALID_PROGRAM) {
|
|
throw new IllegalStateException("Pipeline contains invalid shader program");
|
|
}
|
|
|
|
for (RenderPipeline.UniformDescription uniformDescription : renderPass.pipeline.info().getUniforms()) {
|
|
Object object = renderPass.uniforms.get(uniformDescription.name());
|
|
if (object == null && !GlProgram.BUILT_IN_UNIFORMS.contains(uniformDescription.name())) {
|
|
throw new IllegalStateException("Missing uniform " + uniformDescription.name() + " (should be " + uniformDescription.type() + ")");
|
|
}
|
|
}
|
|
|
|
for (String string : renderPass.pipeline.program().getSamplers()) {
|
|
if (!renderPass.samplers.containsKey(string)) {
|
|
throw new IllegalStateException("Missing sampler " + string);
|
|
}
|
|
|
|
if (((GpuTexture)renderPass.samplers.get(string)).isClosed()) {
|
|
throw new IllegalStateException("Sampler " + string + " has been closed!");
|
|
}
|
|
}
|
|
|
|
if (renderPass.pipeline.info().wantsDepthTexture() && !renderPass.hasDepthTexture()) {
|
|
LOGGER.warn("Render pipeline {} wants a depth texture but none was provided - this is probably a bug", renderPass.pipeline.info().getLocation());
|
|
}
|
|
} else if (renderPass.pipeline == null || renderPass.pipeline.program() == GlProgram.INVALID_PROGRAM) {
|
|
return false;
|
|
}
|
|
|
|
RenderPipeline renderPipeline = renderPass.pipeline.info();
|
|
GlProgram glProgram = renderPass.pipeline.program();
|
|
|
|
for (Uniform uniform : glProgram.getUniforms()) {
|
|
if (renderPass.dirtyUniforms.contains(uniform.getName())) {
|
|
Object object2 = renderPass.uniforms.get(uniform.getName());
|
|
if (object2 instanceof int[]) {
|
|
glProgram.safeGetUniform(uniform.getName()).set((int[])object2);
|
|
} else if (object2 instanceof float[]) {
|
|
glProgram.safeGetUniform(uniform.getName()).set((float[])object2);
|
|
} else if (object2 != null) {
|
|
throw new IllegalStateException("Unknown uniform type - expected " + uniform.getType() + ", found " + object2);
|
|
}
|
|
}
|
|
}
|
|
|
|
renderPass.dirtyUniforms.clear();
|
|
this.applyPipelineState(renderPipeline);
|
|
boolean bl = this.lastProgram != glProgram;
|
|
if (bl) {
|
|
GlStateManager._glUseProgram(glProgram.getProgramId());
|
|
this.lastProgram = glProgram;
|
|
}
|
|
|
|
IntList intList = glProgram.getSamplerLocations();
|
|
|
|
for (int i = 0; i < glProgram.getSamplers().size(); i++) {
|
|
String string2 = (String)glProgram.getSamplers().get(i);
|
|
GlTexture glTexture = (GlTexture)renderPass.samplers.get(string2);
|
|
if (glTexture != null) {
|
|
if (bl || renderPass.dirtySamplers.contains(string2)) {
|
|
int j = intList.getInt(i);
|
|
Uniform.uploadInteger(j, i);
|
|
GlStateManager._activeTexture(33984 + i);
|
|
}
|
|
|
|
GlStateManager._bindTexture(glTexture.glId());
|
|
glTexture.flushModeChanges();
|
|
}
|
|
}
|
|
|
|
Window window = Minecraft.getInstance() == null ? null : Minecraft.getInstance().getWindow();
|
|
glProgram.setDefaultUniforms(
|
|
renderPipeline.getVertexFormatMode(),
|
|
RenderSystem.getModelViewMatrix(),
|
|
RenderSystem.getProjectionMatrix(),
|
|
window == null ? 0.0F : window.getWidth(),
|
|
window == null ? 0.0F : window.getHeight()
|
|
);
|
|
|
|
for (Uniform uniform2 : glProgram.getUniforms()) {
|
|
uniform2.upload();
|
|
}
|
|
|
|
if (renderPass.scissorState.isEnabled()) {
|
|
GlStateManager._enableScissorTest();
|
|
GlStateManager._scissorBox(
|
|
renderPass.scissorState.getX(), renderPass.scissorState.getY(), renderPass.scissorState.getWidth(), renderPass.scissorState.getHeight()
|
|
);
|
|
} else {
|
|
GlStateManager._disableScissorTest();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void applyPipelineState(RenderPipeline pipeline) {
|
|
if (this.lastPipeline != pipeline) {
|
|
this.lastPipeline = pipeline;
|
|
if (pipeline.getDepthTestFunction() != DepthTestFunction.NO_DEPTH_TEST) {
|
|
GlStateManager._enableDepthTest();
|
|
GlStateManager._depthFunc(GlConst.toGl(pipeline.getDepthTestFunction()));
|
|
} else {
|
|
GlStateManager._disableDepthTest();
|
|
}
|
|
|
|
if (pipeline.isCull()) {
|
|
GlStateManager._enableCull();
|
|
} else {
|
|
GlStateManager._disableCull();
|
|
}
|
|
|
|
if (pipeline.getBlendFunction().isPresent()) {
|
|
GlStateManager._enableBlend();
|
|
BlendFunction blendFunction = (BlendFunction)pipeline.getBlendFunction().get();
|
|
GlStateManager._blendFuncSeparate(
|
|
GlConst.toGl(blendFunction.sourceColor()),
|
|
GlConst.toGl(blendFunction.destColor()),
|
|
GlConst.toGl(blendFunction.sourceAlpha()),
|
|
GlConst.toGl(blendFunction.destAlpha())
|
|
);
|
|
} else {
|
|
GlStateManager._disableBlend();
|
|
}
|
|
|
|
GlStateManager._polygonMode(1032, GlConst.toGl(pipeline.getPolygonMode()));
|
|
GlStateManager._depthMask(pipeline.isWriteDepth());
|
|
GlStateManager._colorMask(pipeline.isWriteColor(), pipeline.isWriteColor(), pipeline.isWriteColor(), pipeline.isWriteAlpha());
|
|
if (pipeline.getDepthBiasConstant() == 0.0F && pipeline.getDepthBiasScaleFactor() == 0.0F) {
|
|
GlStateManager._disablePolygonOffset();
|
|
} else {
|
|
GlStateManager._polygonOffset(pipeline.getDepthBiasScaleFactor(), pipeline.getDepthBiasConstant());
|
|
GlStateManager._enablePolygonOffset();
|
|
}
|
|
|
|
switch (pipeline.getColorLogic()) {
|
|
case NONE:
|
|
GlStateManager._disableColorLogicOp();
|
|
break;
|
|
case OR_REVERSE:
|
|
GlStateManager._enableColorLogicOp();
|
|
GlStateManager._logicOp(5387);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void finishRenderPass() {
|
|
this.inRenderPass = false;
|
|
GlStateManager._glBindFramebuffer(36160, 0);
|
|
}
|
|
|
|
protected GlDevice getDevice() {
|
|
return this.device;
|
|
}
|
|
}
|