Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ public void glGetBufferSubData(int target, long offset, ByteBuffer data) {
throw new UnsupportedOperationException("OpenGL ES 2 does not support glGetBufferSubData");
}

@Override
public void glGetBufferSubData(int target, long offset, IntBuffer data) {
throw new UnsupportedOperationException("OpenGL ES 2 does not support glGetBufferSubData");
}

@Override
public void glClear(int mask) {
GLES20.glClear(mask);
Expand Down
184 changes: 184 additions & 0 deletions jme3-core/src/main/java/com/jme3/renderer/opengl/ComputeShader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright (c) 2009-2026 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.renderer.opengl;

import com.jme3.math.Matrix4f;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.renderer.RendererException;
import com.jme3.texture.Texture;
import com.jme3.util.BufferUtils;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

/**
* A compute shader for general-purpose GPU computing (GPGPU).
* <p>
* Compute shaders require OpenGL 4.3 or higher.
*/
public class ComputeShader {

private final GL4 gl;
private final int programId;
/**
* Creates a new compute shader from GLSL source code.
*/
public ComputeShader(GL4 gl, String source) {
this.gl = gl;

// Create and compile the shader
int shaderId = gl.glCreateShader(GL4.GL_COMPUTE_SHADER);
if (shaderId <= 0) {
throw new RendererException("Failed to create compute shader");
}

IntBuffer intBuf = BufferUtils.createIntBuffer(1);
intBuf.clear();
intBuf.put(0, source.length());
gl.glShaderSource(shaderId, new String[]{source}, intBuf);
gl.glCompileShader(shaderId);

// Check compilation status
gl.glGetShader(shaderId, GL.GL_COMPILE_STATUS, intBuf);
if (intBuf.get(0) != GL.GL_TRUE) {
gl.glGetShader(shaderId, GL.GL_INFO_LOG_LENGTH, intBuf);
String infoLog = gl.glGetShaderInfoLog(shaderId, intBuf.get(0));
gl.glDeleteShader(shaderId);
throw new RendererException("Compute shader compilation failed: " + infoLog);
}

// Create program and link
programId = gl.glCreateProgram();
if (programId <= 0) {
gl.glDeleteShader(shaderId);
throw new RendererException("Failed to create shader program");
}

gl.glAttachShader(programId, shaderId);
gl.glLinkProgram(programId);

// Check link status
gl.glGetProgram(programId, GL.GL_LINK_STATUS, intBuf);
if (intBuf.get(0) != GL.GL_TRUE) {
gl.glGetProgram(programId, GL.GL_INFO_LOG_LENGTH, intBuf);
String infoLog = gl.glGetProgramInfoLog(programId, intBuf.get(0));
gl.glDeleteShader(shaderId);
gl.glDeleteProgram(programId);
throw new RendererException("Compute shader program linking failed: " + infoLog);
}

// Shader object can be deleted after linking
gl.glDeleteShader(shaderId);
}

/**
* Activates this compute shader for use.
* Must be called before setting uniforms or dispatching.
*/
public void makeActive() {
gl.glUseProgram(programId);
}

/**
* Dispatches the compute shader with the specified number of work groups.
*/
public void dispatch(int numGroupsX, int numGroupsY, int numGroupsZ) {
gl.glDispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
}

public void bindTexture(int bindingPoint, Texture texture) {
gl.glActiveTexture(GL.GL_TEXTURE0 + bindingPoint);
int textureId = texture.getImage().getId();
int target = convertTextureType(texture);
gl.glBindTexture(target, textureId);
}

public void setUniform(int location, int value) {
gl.glUniform1i(location, value);
}

public void setUniform(int location, float value) {
gl.glUniform1f(location, value);
}

public void setUniform(int location, Vector2f value) {
gl.glUniform2f(location, value.x, value.y);
}

public void setUniform(int location, Vector3f value) {
gl.glUniform3f(location, value.x, value.y, value.z);
}

public void setUniform(int location, Vector4f value) {
gl.glUniform4f(location, value.x, value.y, value.z, value.w);
}

public void setUniform(int location, Matrix4f value) {
FloatBuffer floatBuf16 = BufferUtils.createFloatBuffer(16);
value.fillFloatBuffer(floatBuf16, true);
floatBuf16.clear();
gl.glUniformMatrix4(location, false, floatBuf16);
}

public int getUniformLocation(String name) {
return gl.glGetUniformLocation(programId, name);
}

public void bindShaderStorageBuffer(int location, ShaderStorageBufferObject ssbo) {
gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, location, ssbo.getBufferId());
}

/**
* Deletes this compute shader and releases GPU resources.
* The shader should not be used after calling this method.
*/
public void delete() {
gl.glDeleteProgram(programId);
}

private int convertTextureType(Texture texture) {
switch (texture.getType()) {
case TwoDimensional:
return GL.GL_TEXTURE_2D;
case ThreeDimensional:
return GL2.GL_TEXTURE_3D;
case CubeMap:
return GL.GL_TEXTURE_CUBE_MAP;
case TwoDimensionalArray:
return GLExt.GL_TEXTURE_2D_ARRAY_EXT;
default:
throw new UnsupportedOperationException("Unsupported texture type: " + texture.getType());
}
}
}
10 changes: 10 additions & 0 deletions jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,11 @@ public interface GL {
*/
public void glBufferData(int target, ByteBuffer data, int usage);

/**
* See {@link #glBufferData(int, ByteBuffer, int)}
*/
public void glBufferData(int target, IntBuffer data, int usage);

/**
* <p><a target="_blank" href="http://docs.gl/gl4/glBufferSubData">Reference Page</a></p>
* <p>
Expand Down Expand Up @@ -824,6 +829,11 @@ public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yo
*/
public void glGetBufferSubData(int target, long offset, ByteBuffer data);

/**
* See {@link #glGetBufferSubData(int, long, ByteBuffer)}
*/
public void glGetBufferSubData(int target, long offset, IntBuffer data);

/**
* <p><a target="_blank" href="http://docs.gl/gl4/glGetError">Reference Page</a></p>
*
Expand Down
84 changes: 82 additions & 2 deletions jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ public interface GL4 extends GL3 {
public static final int GL_TESS_EVALUATION_SHADER = 0x8E87;
public static final int GL_PATCHES = 0xE;

/**
* Accepted by the {@code shaderType} parameter of CreateShader.
*/
public static final int GL_COMPUTE_SHADER = 0x91B9;

/**
* Accepted by the {@code barriers} parameter of MemoryBarrier.
*/
public static final int GL_SHADER_STORAGE_BARRIER_BIT = 0x00002000;
public static final int GL_TEXTURE_FETCH_BARRIER_BIT = 0x00000008;

/**
* Accepted by the {@code condition} parameter of FenceSync.
*/
public static final int GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117;

/**
* Returned by ClientWaitSync.
*/
public static final int GL_ALREADY_SIGNALED = 0x911A;
public static final int GL_TIMEOUT_EXPIRED = 0x911B;
public static final int GL_CONDITION_SATISFIED = 0x911C;
public static final int GL_WAIT_FAILED = 0x911D;

/**
* Accepted by the {@code target} parameter of BindBufferBase and BindBufferRange.
*/
Expand Down Expand Up @@ -104,7 +128,7 @@ public interface GL4 extends GL3 {
/**
* Binds a single level of a texture to an image unit for the purpose of reading
* and writing it from shaders.
*
*
* @param unit image unit to bind to
* @param texture texture to bind to the image unit
* @param level level of the texture to bind
Expand All @@ -114,5 +138,61 @@ public interface GL4 extends GL3 {
* @param format format to use when performing formatted stores
*/
public void glBindImageTexture(int unit, int texture, int level, boolean layered, int layer, int access, int format);


/**
* <p><a target="_blank" href="http://docs.gl/gl4/glDispatchCompute">Reference Page</a></p>
* <p>
* Launches one or more compute work groups.
*
* @param numGroupsX the number of work groups to be launched in the X dimension
* @param numGroupsY the number of work groups to be launched in the Y dimension
* @param numGroupsZ the number of work groups to be launched in the Z dimension
*/
public void glDispatchCompute(int numGroupsX, int numGroupsY, int numGroupsZ);

/**
* <p><a target="_blank" href="http://docs.gl/gl4/glMemoryBarrier">Reference Page</a></p>
* <p>
* Defines a barrier ordering memory transactions.
*
* @param barriers the barriers to insert. One or more of:
* {@link #GL_SHADER_STORAGE_BARRIER_BIT}
* {@link #GL_TEXTURE_FETCH_BARRIER_BIT}
*/
public void glMemoryBarrier(int barriers);

/**
* <p><a target="_blank" href="http://docs.gl/gl4/glFenceSync">Reference Page</a></p>
* <p>
* Creates a new sync object and inserts it into the GL command stream.
*
* @param condition the condition that must be met to set the sync object's state to signaled.
* Must be {@link #GL_SYNC_GPU_COMMANDS_COMPLETE}.
* @param flags must be 0
* @return the sync object handle
*/
public long glFenceSync(int condition, int flags);

/**
* <p><a target="_blank" href="http://docs.gl/gl4/glClientWaitSync">Reference Page</a></p>
* <p>
* Causes the client to block and wait for a sync object to become signaled.
*
* @param sync the sync object to wait on
* @param flags flags controlling command flushing behavior. May be 0 or GL_SYNC_FLUSH_COMMANDS_BIT.
* @param timeout the timeout in nanoseconds for which to wait
* @return one of {@link #GL_ALREADY_SIGNALED}, {@link #GL_TIMEOUT_EXPIRED},
* {@link #GL_CONDITION_SATISFIED}, or {@link #GL_WAIT_FAILED}
*/
public int glClientWaitSync(long sync, int flags, long timeout);

/**
* <p><a target="_blank" href="http://docs.gl/gl4/glDeleteSync">Reference Page</a></p>
* <p>
* Deletes a sync object.
*
* @param sync the sync object to delete
*/
public void glDeleteSync(long sync);

}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public void setGenerateMipmapsForFrameBuffer(boolean v) {
generateMipmapsForFramebuffers = v;
}


public void setDebugEnabled(boolean v) {
debug = v;
}
Expand Down Expand Up @@ -3605,4 +3606,9 @@ public boolean isMainFrameBufferSrgb() {
return gl.glIsEnabled(GLExt.GL_FRAMEBUFFER_SRGB_EXT);
}
}

//TODO: How should the GL4 specific functionalities here be exposed? Via the renderer?
public GL4 getGl4(){
return gl4;
}
}
Loading
Loading