/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * org.jspecify.annotations.Nullable * org.lwjgl.opengl.GL11 * org.lwjgl.opengl.GL11C * org.lwjgl.opengl.GL31 * org.lwjgl.opengl.GL32 * org.lwjgl.opengl.GL32C * org.lwjgl.opengl.GL33C * org.slf4j.Logger */ package com.mojang.blaze3d.opengl; import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.GpuFence; import com.mojang.blaze3d.opengl.GlBuffer; import com.mojang.blaze3d.opengl.GlConst; import com.mojang.blaze3d.opengl.GlDevice; import com.mojang.blaze3d.opengl.GlFence; import com.mojang.blaze3d.opengl.GlProgram; import com.mojang.blaze3d.opengl.GlRenderPass; import com.mojang.blaze3d.opengl.GlRenderPipeline; import com.mojang.blaze3d.opengl.GlStateManager; import com.mojang.blaze3d.opengl.GlTexture; import com.mojang.blaze3d.opengl.GlTextureView; import com.mojang.blaze3d.opengl.GlTimerQuery; import com.mojang.blaze3d.opengl.Uniform; 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.shaders.UniformType; import com.mojang.blaze3d.systems.CommandEncoder; import com.mojang.blaze3d.systems.GpuQuery; 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.vertex.VertexFormat; import com.mojang.logging.LogUtils; import java.lang.runtime.SwitchBootstraps; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.function.BiConsumer; import java.util.function.Supplier; import net.minecraft.util.ARGB; import org.jspecify.annotations.Nullable; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11C; import org.lwjgl.opengl.GL31; import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32C; import org.lwjgl.opengl.GL33C; import org.slf4j.Logger; public class GlCommandEncoder implements CommandEncoder { private static final Logger LOGGER = LogUtils.getLogger(); private final GlDevice device; private final int readFbo; private final int drawFbo; private @Nullable RenderPipeline lastPipeline; private boolean inRenderPass; private @Nullable GlProgram lastProgram; private @Nullable GlTimerQuery activeTimerQuery; protected GlCommandEncoder(GlDevice device) { this.device = device; this.readFbo = device.directStateAccess().createFrameBufferObject(); this.drawFbo = device.directStateAccess().createFrameBufferObject(); } @Override public RenderPass createRenderPass(Supplier label, GpuTextureView colorTexture, OptionalInt clearColor) { return this.createRenderPass(label, colorTexture, clearColor, null, OptionalDouble.empty()); } @Override public RenderPass createRenderPass(Supplier label, GpuTextureView colorTexture, OptionalInt clearColor, @Nullable GpuTextureView depthTexture, OptionalDouble clearDepth) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before creating a new one!"); } if (clearDepth.isPresent() && depthTexture == null) { LOGGER.warn("Depth clear value was provided but no depth texture is being used"); } if (colorTexture.isClosed()) { throw new IllegalStateException("Color texture is closed"); } if ((colorTexture.texture().usage() & 8) == 0) { throw new IllegalStateException("Color texture must have USAGE_RENDER_ATTACHMENT"); } if (colorTexture.texture().getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Textures with multiple depths or layers are not yet supported as an attachment"); } if (depthTexture != null) { if (depthTexture.isClosed()) { throw new IllegalStateException("Depth texture is closed"); } if ((depthTexture.texture().usage() & 8) == 0) { throw new IllegalStateException("Depth texture must have USAGE_RENDER_ATTACHMENT"); } if (depthTexture.texture().getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Textures with multiple depths or layers are not yet supported as an attachment"); } } this.inRenderPass = true; this.device.debugLabels().pushDebugGroup(label); int fbo = ((GlTextureView)colorTexture).getFbo(this.device.directStateAccess(), depthTexture == null ? null : depthTexture.texture()); GlStateManager._glBindFramebuffer(36160, fbo); int clearMask = 0; if (clearColor.isPresent()) { int argb = clearColor.getAsInt(); GL11.glClearColor((float)ARGB.redFloat(argb), (float)ARGB.greenFloat(argb), (float)ARGB.blueFloat(argb), (float)ARGB.alphaFloat(argb)); clearMask |= 0x4000; } if (depthTexture != null && clearDepth.isPresent()) { GL11.glClearDepth((double)clearDepth.getAsDouble()); clearMask |= 0x100; } if (clearMask != 0) { GlStateManager._disableScissorTest(); GlStateManager._depthMask(true); GlStateManager._colorMask(true, true, true, true); GlStateManager._clear(clearMask); } GlStateManager._viewport(0, 0, colorTexture.getWidth(0), colorTexture.getHeight(0)); this.lastPipeline = null; return new GlRenderPass(this, depthTexture != null); } @Override public void clearColorTexture(GpuTexture colorTexture, int clearColor) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before creating a new one!"); } this.verifyColorTexture(colorTexture); this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, ((GlTexture)colorTexture).id, 0, 0, 36160); GL11.glClearColor((float)ARGB.redFloat(clearColor), (float)ARGB.greenFloat(clearColor), (float)ARGB.blueFloat(clearColor), (float)ARGB.alphaFloat(clearColor)); 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 colorTexture, int clearColor, GpuTexture depthTexture, double clearDepth) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before creating a new one!"); } this.verifyColorTexture(colorTexture); this.verifyDepthTexture(depthTexture); int fbo = ((GlTexture)colorTexture).getFbo(this.device.directStateAccess(), depthTexture); GlStateManager._glBindFramebuffer(36160, fbo); GlStateManager._disableScissorTest(); GL11.glClearDepth((double)clearDepth); GL11.glClearColor((float)ARGB.redFloat(clearColor), (float)ARGB.greenFloat(clearColor), (float)ARGB.blueFloat(clearColor), (float)ARGB.alphaFloat(clearColor)); GlStateManager._depthMask(true); GlStateManager._colorMask(true, true, true, true); GlStateManager._clear(16640); GlStateManager._glBindFramebuffer(36160, 0); } @Override public void clearColorAndDepthTextures(GpuTexture colorTexture, int clearColor, GpuTexture depthTexture, double clearDepth, int regionX, int regionY, int regionWidth, int regionHeight) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before creating a new one!"); } this.verifyColorTexture(colorTexture); this.verifyDepthTexture(depthTexture); this.verifyRegion(colorTexture, regionX, regionY, regionWidth, regionHeight); int fbo = ((GlTexture)colorTexture).getFbo(this.device.directStateAccess(), depthTexture); GlStateManager._glBindFramebuffer(36160, fbo); GlStateManager._scissorBox(regionX, regionY, regionWidth, regionHeight); GlStateManager._enableScissorTest(); GL11.glClearDepth((double)clearDepth); GL11.glClearColor((float)ARGB.redFloat(clearColor), (float)ARGB.greenFloat(clearColor), (float)ARGB.blueFloat(clearColor), (float)ARGB.alphaFloat(clearColor)); GlStateManager._depthMask(true); GlStateManager._colorMask(true, true, true, true); GlStateManager._clear(16640); GlStateManager._glBindFramebuffer(36160, 0); } private void verifyRegion(GpuTexture colorTexture, int regionX, int regionY, int regionWidth, int regionHeight) { if (regionX < 0 || regionX >= colorTexture.getWidth(0)) { throw new IllegalArgumentException("regionX should not be outside of the texture"); } if (regionY < 0 || regionY >= colorTexture.getHeight(0)) { throw new IllegalArgumentException("regionY should not be outside of the texture"); } if (regionWidth <= 0) { throw new IllegalArgumentException("regionWidth should be greater than 0"); } if (regionX + regionWidth > colorTexture.getWidth(0)) { throw new IllegalArgumentException("regionWidth + regionX should be less than the texture width"); } if (regionHeight <= 0) { throw new IllegalArgumentException("regionHeight should be greater than 0"); } if (regionY + regionHeight > colorTexture.getHeight(0)) { throw new IllegalArgumentException("regionWidth + regionX should be less than the texture height"); } } @Override public void clearDepthTexture(GpuTexture depthTexture, double clearDepth) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before creating a new one!"); } this.verifyDepthTexture(depthTexture); this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, 0, ((GlTexture)depthTexture).id, 0, 36160); GL11.glDrawBuffer((int)0); GL11.glClearDepth((double)clearDepth); GlStateManager._depthMask(true); GlStateManager._disableScissorTest(); GlStateManager._clear(256); GL11.glDrawBuffer((int)36064); GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, 0, 0); GlStateManager._glBindFramebuffer(36160, 0); } private void verifyColorTexture(GpuTexture colorTexture) { if (!colorTexture.getFormat().hasColorAspect()) { throw new IllegalStateException("Trying to clear a non-color texture as color"); } if (colorTexture.isClosed()) { throw new IllegalStateException("Color texture is closed"); } if ((colorTexture.usage() & 8) == 0) { throw new IllegalStateException("Color texture must have USAGE_RENDER_ATTACHMENT"); } if (colorTexture.getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Clearing a texture with multiple layers or depths is not yet supported"); } } private void verifyDepthTexture(GpuTexture depthTexture) { if (!depthTexture.getFormat().hasDepthAspect()) { throw new IllegalStateException("Trying to clear a non-depth texture as depth"); } if (depthTexture.isClosed()) { throw new IllegalStateException("Depth texture is closed"); } if ((depthTexture.usage() & 8) == 0) { throw new IllegalStateException("Depth texture must have USAGE_RENDER_ATTACHMENT"); } if (depthTexture.getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Clearing a texture with multiple layers or depths is not yet supported"); } } @Override public void writeToBuffer(GpuBufferSlice slice, ByteBuffer data) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } GlBuffer buffer = (GlBuffer)slice.buffer(); if (buffer.closed) { throw new IllegalStateException("Buffer already closed"); } if ((buffer.usage() & 8) == 0) { throw new IllegalStateException("Buffer needs USAGE_COPY_DST to be a destination for a copy"); } int length = data.remaining(); if (length > slice.length()) { throw new IllegalArgumentException("Cannot write more data than the slice allows (attempting to write " + length + " bytes into a slice of length " + slice.length() + ")"); } if (slice.length() + slice.offset() > buffer.size()) { throw new IllegalArgumentException("Cannot write more data than this buffer can hold (attempting to write " + length + " bytes at offset " + slice.offset() + " to " + buffer.size() + " size buffer)"); } this.device.directStateAccess().bufferSubData(buffer.handle, slice.offset(), data, buffer.usage()); } @Override public GpuBuffer.MappedView mapBuffer(GpuBuffer buffer, boolean read, boolean write) { return this.mapBuffer(buffer.slice(), read, write); } @Override public GpuBuffer.MappedView mapBuffer(GpuBufferSlice slice, boolean read, boolean write) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } GlBuffer buffer = (GlBuffer)slice.buffer(); if (buffer.closed) { throw new IllegalStateException("Buffer already closed"); } if (!read && !write) { throw new IllegalArgumentException("At least read or write must be true"); } if (read && (buffer.usage() & 1) == 0) { throw new IllegalStateException("Buffer is not readable"); } if (write && (buffer.usage() & 2) == 0) { throw new IllegalStateException("Buffer is not writable"); } if (slice.offset() + slice.length() > buffer.size()) { throw new IllegalArgumentException("Cannot map more data than this buffer can hold (attempting to map " + slice.length() + " bytes at offset " + slice.offset() + " from " + buffer.size() + " size buffer)"); } int flags = 0; if (read) { flags |= 1; } if (write) { flags |= 0x22; } return this.device.getBufferStorage().mapBuffer(this.device.directStateAccess(), buffer, slice.offset(), slice.length(), flags); } @Override public void copyToBuffer(GpuBufferSlice source, GpuBufferSlice target) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } GlBuffer sourceBuffer = (GlBuffer)source.buffer(); if (sourceBuffer.closed) { throw new IllegalStateException("Source buffer already closed"); } if ((sourceBuffer.usage() & 0x10) == 0) { throw new IllegalStateException("Source buffer needs USAGE_COPY_SRC to be a source for a copy"); } GlBuffer targetBuffer = (GlBuffer)target.buffer(); if (targetBuffer.closed) { throw new IllegalStateException("Target buffer already closed"); } if ((targetBuffer.usage() & 8) == 0) { throw new IllegalStateException("Target buffer needs USAGE_COPY_DST to be a destination for a copy"); } if (source.length() != target.length()) { throw new IllegalArgumentException("Cannot copy from slice of size " + source.length() + " to slice of size " + target.length() + ", they must be equal"); } if (source.offset() + source.length() > sourceBuffer.size()) { throw new IllegalArgumentException("Cannot copy more data than the source buffer holds (attempting to copy " + source.length() + " bytes at offset " + source.offset() + " from " + sourceBuffer.size() + " size buffer)"); } if (target.offset() + target.length() > targetBuffer.size()) { throw new IllegalArgumentException("Cannot copy more data than the target buffer can hold (attempting to copy " + target.length() + " bytes at offset " + target.offset() + " to " + targetBuffer.size() + " size buffer)"); } this.device.directStateAccess().copyBufferSubData(sourceBuffer.handle, targetBuffer.handle, source.offset(), target.offset(), source.length()); } @Override public void writeToTexture(GpuTexture destination, NativeImage source) { int width = destination.getWidth(0); int height = destination.getHeight(0); if (source.getWidth() != width || source.getHeight() != height) { throw new IllegalArgumentException("Cannot replace texture of size " + width + "x" + height + " with image of size " + source.getWidth() + "x" + source.getHeight()); } if (destination.isClosed()) { throw new IllegalStateException("Destination texture is closed"); } if ((destination.usage() & 1) == 0) { throw new IllegalStateException("Color texture must have USAGE_COPY_DST to be a destination for a write"); } this.writeToTexture(destination, source, 0, 0, 0, 0, width, height, 0, 0); } @Override public void writeToTexture(GpuTexture destination, NativeImage source, int mipLevel, int depthOrLayer, int destX, int destY, int width, int height, int sourceX, int sourceY) { int target; if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } if (mipLevel < 0 || mipLevel >= destination.getMipLevels()) { throw new IllegalArgumentException("Invalid mipLevel " + mipLevel + ", must be >= 0 and < " + destination.getMipLevels()); } if (sourceX + width > source.getWidth() || sourceY + height > source.getHeight()) { throw new IllegalArgumentException("Copy source (" + source.getWidth() + "x" + source.getHeight() + ") is not large enough to read a rectangle of " + width + "x" + height + " from " + sourceX + "x" + sourceY); } if (destX + width > destination.getWidth(mipLevel) || destY + height > destination.getHeight(mipLevel)) { throw new IllegalArgumentException("Dest texture (" + width + "x" + height + ") is not large enough to write a rectangle of " + width + "x" + height + " at " + destX + "x" + destY + " (at mip level " + mipLevel + ")"); } if (destination.isClosed()) { throw new IllegalStateException("Destination texture is closed"); } if ((destination.usage() & 1) == 0) { throw new IllegalStateException("Color texture must have USAGE_COPY_DST to be a destination for a write"); } if (depthOrLayer >= destination.getDepthOrLayers()) { throw new UnsupportedOperationException("Depth or layer is out of range, must be >= 0 and < " + destination.getDepthOrLayers()); } if ((destination.usage() & 0x10) != 0) { target = GlConst.CUBEMAP_TARGETS[depthOrLayer % 6]; GL11.glBindTexture((int)34067, (int)((GlTexture)destination).id); } else { target = 3553; GlStateManager._bindTexture(((GlTexture)destination).id); } GlStateManager._pixelStore(3314, source.getWidth()); GlStateManager._pixelStore(3316, sourceX); GlStateManager._pixelStore(3315, sourceY); GlStateManager._pixelStore(3317, source.format().components()); GlStateManager._texSubImage2D(target, mipLevel, destX, destY, width, height, GlConst.toGl(source.format()), 5121, source.getPointer()); } @Override public void writeToTexture(GpuTexture destination, ByteBuffer source, NativeImage.Format format, int mipLevel, int depthOrLayer, int destX, int destY, int width, int height) { int target; if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } if (mipLevel < 0 || mipLevel >= destination.getMipLevels()) { throw new IllegalArgumentException("Invalid mipLevel, must be >= 0 and < " + destination.getMipLevels()); } if (width * height * format.components() > source.remaining()) { throw new IllegalArgumentException("Copy would overrun the source buffer (remaining length of " + source.remaining() + ", but copy is " + width + "x" + height + " of format " + String.valueOf((Object)format) + ")"); } if (destX + width > destination.getWidth(mipLevel) || destY + height > destination.getHeight(mipLevel)) { throw new IllegalArgumentException("Dest texture (" + destination.getWidth(mipLevel) + "x" + destination.getHeight(mipLevel) + ") is not large enough to write a rectangle of " + width + "x" + height + " at " + destX + "x" + destY); } if (destination.isClosed()) { throw new IllegalStateException("Destination texture is closed"); } if ((destination.usage() & 1) == 0) { throw new IllegalStateException("Color texture must have USAGE_COPY_DST to be a destination for a write"); } if (depthOrLayer >= destination.getDepthOrLayers()) { throw new UnsupportedOperationException("Depth or layer is out of range, must be >= 0 and < " + destination.getDepthOrLayers()); } if ((destination.usage() & 0x10) != 0) { target = GlConst.CUBEMAP_TARGETS[depthOrLayer % 6]; GL11.glBindTexture((int)34067, (int)((GlTexture)destination).id); } else { target = 3553; GlStateManager._bindTexture(((GlTexture)destination).id); } GlStateManager._pixelStore(3314, width); GlStateManager._pixelStore(3316, 0); GlStateManager._pixelStore(3315, 0); GlStateManager._pixelStore(3317, format.components()); GlStateManager._texSubImage2D(target, mipLevel, destX, destY, width, height, GlConst.toGl(format), 5121, source); } @Override public void copyTextureToBuffer(GpuTexture source, GpuBuffer destination, int offset, Runnable callback, int mipLevel) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } this.copyTextureToBuffer(source, destination, offset, callback, mipLevel, 0, 0, source.getWidth(mipLevel), source.getHeight(mipLevel)); } @Override public void copyTextureToBuffer(GpuTexture source, GpuBuffer destination, int offset, Runnable callback, int mipLevel, int x, int y, int width, int height) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } if (mipLevel < 0 || mipLevel >= source.getMipLevels()) { throw new IllegalArgumentException("Invalid mipLevel " + mipLevel + ", must be >= 0 and < " + source.getMipLevels()); } if (source.getWidth(mipLevel) * source.getHeight(mipLevel) * source.getFormat().pixelSize() + offset > destination.size()) { throw new IllegalArgumentException("Buffer of size " + destination.size() + " is not large enough to hold " + width + "x" + height + " pixels (" + source.getFormat().pixelSize() + " bytes each) starting from offset " + offset); } if ((source.usage() & 2) == 0) { throw new IllegalArgumentException("Texture needs USAGE_COPY_SRC to be a source for a copy"); } if ((destination.usage() & 8) == 0) { throw new IllegalArgumentException("Buffer needs USAGE_COPY_DST to be a destination for a copy"); } if (x + width > source.getWidth(mipLevel) || y + height > source.getHeight(mipLevel)) { throw new IllegalArgumentException("Copy source texture (" + source.getWidth(mipLevel) + "x" + source.getHeight(mipLevel) + ") is not large enough to read a rectangle of " + width + "x" + height + " from " + x + "," + y); } if (source.isClosed()) { throw new IllegalStateException("Source texture is closed"); } if (destination.isClosed()) { throw new IllegalStateException("Destination buffer is closed"); } if (source.getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Textures with multiple depths or layers are not yet supported for copying"); } GlStateManager.clearGlErrors(); this.device.directStateAccess().bindFrameBufferTextures(this.readFbo, ((GlTexture)source).glId(), 0, mipLevel, 36008); GlStateManager._glBindBuffer(35051, ((GlBuffer)destination).handle); GlStateManager._pixelStore(3330, width); GlStateManager._readPixels(x, y, width, height, GlConst.toGlExternalId(source.getFormat()), GlConst.toGlType(source.getFormat()), offset); RenderSystem.queueFencedTask(callback); GlStateManager._glFramebufferTexture2D(36008, 36064, 3553, 0, mipLevel); GlStateManager._glBindFramebuffer(36008, 0); GlStateManager._glBindBuffer(35051, 0); int error = GlStateManager._getError(); if (error != 0) { throw new IllegalStateException("Couldn't perform copyTobuffer for texture " + source.getLabel() + ": GL error " + error); } } @Override public void copyTextureToTexture(GpuTexture source, GpuTexture destination, int mipLevel, int destX, int destY, int sourceX, int sourceY, int width, int height) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } if (mipLevel < 0 || mipLevel >= source.getMipLevels() || mipLevel >= destination.getMipLevels()) { throw new IllegalArgumentException("Invalid mipLevel " + mipLevel + ", must be >= 0 and < " + source.getMipLevels() + " and < " + destination.getMipLevels()); } if (destX + width > destination.getWidth(mipLevel) || destY + height > destination.getHeight(mipLevel)) { throw new IllegalArgumentException("Dest texture (" + destination.getWidth(mipLevel) + "x" + destination.getHeight(mipLevel) + ") is not large enough to write a rectangle of " + width + "x" + height + " at " + destX + "x" + destY); } if (sourceX + width > source.getWidth(mipLevel) || sourceY + height > source.getHeight(mipLevel)) { throw new IllegalArgumentException("Source texture (" + source.getWidth(mipLevel) + "x" + source.getHeight(mipLevel) + ") is not large enough to read a rectangle of " + width + "x" + height + " at " + sourceX + "x" + sourceY); } if (source.isClosed()) { throw new IllegalStateException("Source texture is closed"); } if (destination.isClosed()) { throw new IllegalStateException("Destination texture is closed"); } if ((source.usage() & 2) == 0) { throw new IllegalArgumentException("Texture needs USAGE_COPY_SRC to be a source for a copy"); } if ((destination.usage() & 1) == 0) { throw new IllegalArgumentException("Texture needs USAGE_COPY_DST to be a destination for a copy"); } if (source.getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Textures with multiple depths or layers are not yet supported for copying"); } if (destination.getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Textures with multiple depths or layers are not yet supported for copying"); } GlStateManager.clearGlErrors(); GlStateManager._disableScissorTest(); boolean isDepth = source.getFormat().hasDepthAspect(); int sourceId = ((GlTexture)source).glId(); int destId = ((GlTexture)destination).glId(); this.device.directStateAccess().bindFrameBufferTextures(this.readFbo, isDepth ? 0 : sourceId, isDepth ? sourceId : 0, 0, 0); this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, isDepth ? 0 : destId, isDepth ? destId : 0, 0, 0); this.device.directStateAccess().blitFrameBuffers(this.readFbo, this.drawFbo, sourceX, sourceY, width, height, destX, destY, width, height, isDepth ? 256 : 16384, 9728); int error = GlStateManager._getError(); if (error != 0) { throw new IllegalStateException("Couldn't perform copyToTexture for texture " + source.getLabel() + " to " + destination.getLabel() + ": GL error " + error); } } @Override public void presentTexture(GpuTextureView textureView) { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } if (!textureView.texture().getFormat().hasColorAspect()) { throw new IllegalStateException("Cannot present a non-color texture!"); } if ((textureView.texture().usage() & 8) == 0) { throw new IllegalStateException("Color texture must have USAGE_RENDER_ATTACHMENT to presented to the screen"); } if (textureView.texture().getDepthOrLayers() > 1) { throw new UnsupportedOperationException("Textures with multiple depths or layers are not yet supported for presentation"); } GlStateManager._disableScissorTest(); GlStateManager._viewport(0, 0, textureView.getWidth(0), textureView.getHeight(0)); GlStateManager._depthMask(true); GlStateManager._colorMask(true, true, true, true); this.device.directStateAccess().bindFrameBufferTextures(this.drawFbo, ((GlTexture)textureView.texture()).glId(), 0, 0, 0); this.device.directStateAccess().blitFrameBuffers(this.drawFbo, 0, 0, 0, textureView.getWidth(0), textureView.getHeight(0), 0, 0, textureView.getWidth(0), textureView.getHeight(0), 16384, 9728); } @Override public GpuFence createFence() { if (this.inRenderPass) { throw new IllegalStateException("Close the existing render pass before performing additional commands"); } return new GlFence(); } protected void executeDrawMultiple(GlRenderPass renderPass, Collection> draws, @Nullable GpuBuffer defaultIndexBuffer, @Nullable VertexFormat.IndexType defaultIndexType, Collection dynamicUniforms, T uniformArgument) { if (!this.trySetup(renderPass, dynamicUniforms)) { return; } if (defaultIndexType == null) { defaultIndexType = VertexFormat.IndexType.SHORT; } for (RenderPass.Draw draw : draws) { BiConsumer uniformUploaderConsumer; VertexFormat.IndexType indexType = draw.indexType() == null ? defaultIndexType : draw.indexType(); renderPass.setIndexBuffer(draw.indexBuffer() == null ? defaultIndexBuffer : draw.indexBuffer(), indexType); 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!"); } } if ((uniformUploaderConsumer = draw.uniformUploaderConsumer()) != null) { uniformUploaderConsumer.accept(uniformArgument, (name, buffer) -> { Uniform patt1$temp = renderPass.pipeline.program().getUniform(name); if (patt1$temp instanceof Uniform.Ubo) { int blockBinding; Uniform.Ubo $b$0 = (Uniform.Ubo)patt1$temp; try { int patt2$temp; blockBinding = patt2$temp = $b$0.blockBinding(); } catch (Throwable throwable) { throw new MatchException(throwable.toString(), throwable); } GL32.glBindBufferRange((int)35345, (int)blockBinding, (int)((GlBuffer)buffer.buffer()).handle, (long)buffer.offset(), (long)buffer.length()); } }); } this.drawFromBuffers(renderPass, 0, draw.firstIndex(), draw.indexCount(), indexType, renderPass.pipeline, 1); } } protected void executeDraw(GlRenderPass renderPass, int baseVertex, int firstIndex, int drawCount, @Nullable VertexFormat.IndexType indexType, int instanceCount) { if (!this.trySetup(renderPass, Collections.emptyList())) { return; } 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.indexBuffer.usage() & 0x40) == 0) { throw new IllegalStateException("Index buffer must have GpuBuffer.USAGE_INDEX!"); } } GlRenderPipeline pipeline = renderPass.pipeline; if (renderPass.vertexBuffers[0] == null && pipeline != null && !pipeline.info().getVertexFormat().getElements().isEmpty()) { throw new IllegalStateException("Vertex format contains elements but vertex buffer at slot 0 is null"); } if (renderPass.vertexBuffers[0] != null && renderPass.vertexBuffers[0].isClosed()) { throw new IllegalStateException("Vertex buffer at slot 0 has been closed!"); } if (renderPass.vertexBuffers[0] != null && (renderPass.vertexBuffers[0].usage() & 0x20) == 0) { throw new IllegalStateException("Vertex buffer must have GpuBuffer.USAGE_VERTEX!"); } } this.drawFromBuffers(renderPass, baseVertex, firstIndex, drawCount, indexType, renderPass.pipeline, instanceCount); } private void drawFromBuffers(GlRenderPass renderPass, int baseVertex, int firstIndex, int drawCount, @Nullable VertexFormat.IndexType indexType, GlRenderPipeline pipeline, int instanceCount) { this.device.vertexArrayCache().bindVertexArray(pipeline.info().getVertexFormat(), (GlBuffer)renderPass.vertexBuffers[0]); if (indexType != null) { GlStateManager._glBindBuffer(34963, ((GlBuffer)renderPass.indexBuffer).handle); if (instanceCount > 1) { if (baseVertex > 0) { GL32.glDrawElementsInstancedBaseVertex((int)GlConst.toGl(pipeline.info().getVertexFormatMode()), (int)drawCount, (int)GlConst.toGl(indexType), (long)((long)firstIndex * (long)indexType.bytes), (int)instanceCount, (int)baseVertex); } else { GL31.glDrawElementsInstanced((int)GlConst.toGl(pipeline.info().getVertexFormatMode()), (int)drawCount, (int)GlConst.toGl(indexType), (long)((long)firstIndex * (long)indexType.bytes), (int)instanceCount); } } else if (baseVertex > 0) { GL32.glDrawElementsBaseVertex((int)GlConst.toGl(pipeline.info().getVertexFormatMode()), (int)drawCount, (int)GlConst.toGl(indexType), (long)((long)firstIndex * (long)indexType.bytes), (int)baseVertex); } else { GlStateManager._drawElements(GlConst.toGl(pipeline.info().getVertexFormatMode()), drawCount, GlConst.toGl(indexType), (long)firstIndex * (long)indexType.bytes); } } else if (instanceCount > 1) { GL31.glDrawArraysInstanced((int)GlConst.toGl(pipeline.info().getVertexFormatMode()), (int)baseVertex, (int)drawCount, (int)instanceCount); } else { GlStateManager._drawArrays(GlConst.toGl(pipeline.info().getVertexFormatMode()), baseVertex, drawCount); } } /* * Could not resolve type clashes * Unable to fully structure code */ private boolean trySetup(GlRenderPass renderPass, Collection dynamicUniforms) { 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 uniform : renderPass.pipeline.info().getUniforms()) { value = renderPass.uniforms.get(uniform.name()); if (dynamicUniforms.contains(uniform.name())) continue; if (value == null) { throw new IllegalStateException("Missing uniform " + uniform.name() + " (should be " + String.valueOf((Object)uniform.type()) + ")"); } if (uniform.type() == UniformType.UNIFORM_BUFFER) { if (value.buffer().isClosed()) { throw new IllegalStateException("Uniform buffer " + uniform.name() + " is already closed"); } if ((value.buffer().usage() & 128) == 0) { throw new IllegalStateException("Uniform buffer " + uniform.name() + " must have GpuBuffer.USAGE_UNIFORM"); } } if (uniform.type() != UniformType.TEXEL_BUFFER) continue; if (value.offset() != 0 || value.length() != value.buffer().size()) { throw new IllegalStateException("Uniform texel buffers do not support a slice of a buffer, must be entire buffer"); } if (uniform.textureFormat() != null) continue; throw new IllegalStateException("Invalid uniform texel buffer " + uniform.name() + " (missing a texture format)"); } for (Map.Entry entry : renderPass.pipeline.program().getUniforms().entrySet()) { if (!(entry.getValue() instanceof Uniform.Sampler)) continue; name = (String)entry.getKey(); viewAndSampler = renderPass.samplers.get(name); if (viewAndSampler == null) { throw new IllegalStateException("Missing sampler " + name); } textureView = viewAndSampler.view(); if (textureView.isClosed()) { throw new IllegalStateException("Texture view " + name + " (" + textureView.texture().getLabel() + ") has been closed!"); } if ((textureView.texture().usage() & 4) == 0) { throw new IllegalStateException("Texture view " + name + " (" + textureView.texture().getLabel() + ") must have USAGE_TEXTURE_BINDING!"); } if (!viewAndSampler.sampler().isClosed()) continue; throw new IllegalStateException("Sampler for " + name + " (" + textureView.texture().getLabel() + ") has been closed!"); } if (renderPass.pipeline.info().wantsDepthTexture() && !renderPass.hasDepthTexture()) { GlCommandEncoder.LOGGER.warn("Render pipeline {} wants a depth texture but none was provided - this is probably a bug", (Object)renderPass.pipeline.info().getLocation()); } } else if (renderPass.pipeline == null || renderPass.pipeline.program() == GlProgram.INVALID_PROGRAM) { return false; } pipeline = renderPass.pipeline.info(); glProgram = renderPass.pipeline.program(); this.applyPipelineState(pipeline); v0 = differentProgram = this.lastProgram != glProgram; if (differentProgram) { GlStateManager._glUseProgram(glProgram.getProgramId()); this.lastProgram = glProgram; } block15: for (Map.Entry entry : glProgram.getUniforms().entrySet()) { block35: { name = entry.getKey(); isDirty = renderPass.dirtyUniforms.contains(name); Objects.requireNonNull(entry.getValue()); var11_13 = 0; switch (SwitchBootstraps.typeSwitch("typeSwitch", new Object[]{Uniform.Ubo.class, Uniform.Utb.class, Uniform.Sampler.class}, (Object)var10_12, var11_13)) { default: { throw new MatchException(null, null); } case 0: { var12_14 = (Uniform.Ubo)var10_12; blockBinding = var14_16 = var12_14.blockBinding(); if (!isDirty) continue block15; bufferView = renderPass.uniforms.get(name); GL32.glBindBufferRange((int)35345, (int)blockBinding, (int)((GlBuffer)bufferView.buffer()).handle, (long)bufferView.offset(), (long)bufferView.length()); continue block15; } case 1: { var14_18 = (Uniform.Utb)var10_12; location = var19_23 = var14_18.location(); samplerIndex = var19_23 = var14_18.samplerIndex(); format = var19_24 = var14_18.format(); texture = var19_25 = var14_18.texture(); if (!differentProgram && !isDirty) ** GOTO lbl75 GlStateManager._glUniform1i(location, samplerIndex); lbl75: // 2 sources GlStateManager._activeTexture(33984 + samplerIndex); GL11C.glBindTexture((int)35882, (int)texture); if (!isDirty) continue block15; bufferView = renderPass.uniforms.get(name); GL31.glTexBuffer((int)35882, (int)GlConst.toGlInternalId(format), (int)((GlBuffer)bufferView.buffer()).handle); continue block15; } case 2: } var19_27 = (Uniform.Sampler)var10_12; location = var22_31 = var19_27.location(); samplerIndex = var22_31 = var19_27.samplerIndex(); viewAndSampler = renderPass.samplers.get(name); if (viewAndSampler == null) continue; textureView = viewAndSampler.view(); if (!differentProgram && !isDirty) break block35; GlStateManager._glUniform1i(location, samplerIndex); } GlStateManager._activeTexture(33984 + samplerIndex); texture = textureView.texture(); if ((texture.usage() & 16) != 0) { target = 34067; GL11.glBindTexture((int)34067, (int)texture.id); } else { target = 3553; GlStateManager._bindTexture(texture.id); } GL33C.glBindSampler((int)samplerIndex, (int)viewAndSampler.sampler().getId()); GlStateManager._texParameter(target, 33084, textureView.baseMipLevel()); GlStateManager._texParameter(target, 33085, textureView.baseMipLevel() + textureView.mipLevels() - 1); } renderPass.dirtyUniforms.clear(); if (renderPass.isScissorEnabled()) { GlStateManager._enableScissorTest(); GlStateManager._scissorBox(renderPass.getScissorX(), renderPass.getScissorY(), renderPass.getScissorWidth(), renderPass.getScissorHeight()); } else { GlStateManager._disableScissorTest(); } return true; catch (Throwable var6_8) { throw new MatchException(var6_8.toString(), var6_8); } } private void applyPipelineState(RenderPipeline pipeline) { if (this.lastPipeline == pipeline) { return; } 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 = 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._polygonOffset(pipeline.getDepthBiasScaleFactor(), pipeline.getDepthBiasConstant()); GlStateManager._enablePolygonOffset(); } else { GlStateManager._disablePolygonOffset(); } 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); this.device.debugLabels().popDebugGroup(); } protected GlDevice getDevice() { return this.device; } @Override public GpuQuery timerQueryBegin() { RenderSystem.assertOnRenderThread(); if (this.activeTimerQuery != null) { throw new IllegalStateException("A GL_TIME_ELAPSED query is already active"); } int queryId = GL32C.glGenQueries(); GL32C.glBeginQuery((int)35007, (int)queryId); this.activeTimerQuery = new GlTimerQuery(queryId); return this.activeTimerQuery; } @Override public void timerQueryEnd(GpuQuery query) { RenderSystem.assertOnRenderThread(); if (query != this.activeTimerQuery) { throw new IllegalStateException("Mismatched or duplicate GpuQuery when ending timerQuery"); } GL32C.glEndQuery((int)35007); this.activeTimerQuery = null; } }